+
From 00fe1dda07eed10bd271b41558fab961244a2279 Mon Sep 17 00:00:00 2001
From: Juha Luoma <33253757+LuomaJuha@users.noreply.github.com>
Date: Mon, 13 Jan 2025 12:59:29 +0200
Subject: [PATCH 13/24] Adjusted comments
---
.../src/Finna/AjaxHandler/AbstractIlsAndUserActionFactory.php | 3 +++
1 file changed, 3 insertions(+)
diff --git a/module/Finna/src/Finna/AjaxHandler/AbstractIlsAndUserActionFactory.php b/module/Finna/src/Finna/AjaxHandler/AbstractIlsAndUserActionFactory.php
index d296a8e897e..dfcb42eea5d 100644
--- a/module/Finna/src/Finna/AjaxHandler/AbstractIlsAndUserActionFactory.php
+++ b/module/Finna/src/Finna/AjaxHandler/AbstractIlsAndUserActionFactory.php
@@ -6,6 +6,7 @@
* PHP version 8
*
* Copyright (C) Villanova University 2018.
+ * Copyright (C) The National Library of Finland 2024.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
@@ -23,6 +24,7 @@
* @category VuFind
* @package AJAX
* @author Demian Katz
+ * @author Juha Luoma
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org/wiki/development Wiki
*/
@@ -40,6 +42,7 @@
* @category VuFind
* @package AJAX
* @author Demian Katz
+ * @author Juha Luoma
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org/wiki/development Wiki
*/
From 7ab30395bddb29bcd46ce2ca7628f5d04ba489bf Mon Sep 17 00:00:00 2001
From: Juha Luoma <33253757+LuomaJuha@users.noreply.github.com>
Date: Mon, 13 Jan 2025 13:05:20 +0200
Subject: [PATCH 14/24] Removed unused use
---
module/Finna/src/Finna/AjaxHandler/GetTransactionHistory.php | 1 -
1 file changed, 1 deletion(-)
diff --git a/module/Finna/src/Finna/AjaxHandler/GetTransactionHistory.php b/module/Finna/src/Finna/AjaxHandler/GetTransactionHistory.php
index 9fc0a95e58e..9a538c83e0b 100644
--- a/module/Finna/src/Finna/AjaxHandler/GetTransactionHistory.php
+++ b/module/Finna/src/Finna/AjaxHandler/GetTransactionHistory.php
@@ -31,7 +31,6 @@
namespace Finna\AjaxHandler;
-use Exception;
use Laminas\Mvc\Controller\Plugin\Params;
use PhpOffice\PhpSpreadsheet\Cell\AdvancedValueBinder;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
From e473b625c55fa2b1c3a7235e1c7aa48093d698c6 Mon Sep 17 00:00:00 2001
From: Juha Luoma <33253757+LuomaJuha@users.noreply.github.com>
Date: Wed, 15 Jan 2025 19:37:54 +0200
Subject: [PATCH 15/24] Changed naming from transactions to checkouts
---
module/Finna/config/module.config.php | 9 +-
.../Finna/AjaxHandler/GetCheckoutHistory.php | 140 ++++++++++++++++++
...tory.php => GetCheckoutHistoryFactory.php} | 20 +--
...History.php => GetCheckoutHistoryFile.php} | 134 +++++------------
.../src/Finna/Controller/AjaxController.php | 53 +++----
.../Finna/Controller/MyResearchController.php | 2 +-
...n-history.js => finna-checkout-history.js} | 90 +++++------
themes/finna2/js/finna.js | 1 -
.../finna2/templates/checkouts/history.phtml | 10 ++
themes/finna2/theme.config.php | 2 +-
10 files changed, 278 insertions(+), 183 deletions(-)
create mode 100644 module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php
rename module/Finna/src/Finna/AjaxHandler/{AbstractIlsAndUserActionFactory.php => GetCheckoutHistoryFactory.php} (78%)
rename module/Finna/src/Finna/AjaxHandler/{GetTransactionHistory.php => GetCheckoutHistoryFile.php} (64%)
rename themes/finna2/js/{finna-transaction-history.js => finna-checkout-history.js} (54%)
diff --git a/module/Finna/config/module.config.php b/module/Finna/config/module.config.php
index 82e28964add..a4e6d1f8e02 100644
--- a/module/Finna/config/module.config.php
+++ b/module/Finna/config/module.config.php
@@ -495,8 +495,10 @@
'Finna\AjaxHandler\GetUserListFactory',
'Finna\AjaxHandler\GetUserLists' =>
'Finna\AjaxHandler\GetUserListsFactory',
- 'Finna\AjaxHandler\GetTransactionHistory' =>
- 'Finna\AjaxHandler\AbstractIlsAndUserActionFactory',
+ 'Finna\AjaxHandler\GetCheckoutHistory' =>
+ 'Finna\AjaxHandler\GetCheckoutHistoryFactory',
+ 'Finna\AjaxHandler\GetCheckoutHistoryFile' =>
+ 'Finna\AjaxHandler\GetCheckoutHistoryFactory',
'Finna\AjaxHandler\ReservationList' =>
'Finna\AjaxHandler\ReservationListFactory',
'Finna\AjaxHandler\ImportFavorites' =>
@@ -519,6 +521,8 @@
'getAccountNotifications' => 'Finna\AjaxHandler\GetAccountNotifications',
'getAuthorityInfo' => 'Finna\AjaxHandler\GetAuthorityInfo',
'getAuthorityFullInfo' => 'Finna\AjaxHandler\GetAuthorityFullInfo',
+ 'getCheckoutHistory' => 'Finna\AjaxHandler\GetCheckoutHistory',
+ 'getCheckoutHistoryFile' => 'Finna\AjaxHandler\GetCheckoutHistoryFile',
'getContentFeed' => 'Finna\AjaxHandler\GetContentFeed',
'getDescription' => 'Finna\AjaxHandler\GetDescription',
'getModel' => 'Finna\AjaxHandler\GetModel',
@@ -536,7 +540,6 @@
'getRecordData' => 'Finna\AjaxHandler\GetRecordData',
'getRecordDriverRelatedRecords' => 'Finna\AjaxHandler\GetRecordDriverRelatedRecords',
'getRecordInfoByAuthority' => 'Finna\AjaxHandler\GetRecordInfoByAuthority',
- 'getTransactionHistory' => 'Finna\AjaxHandler\GetTransactionHistory',
'getSearchTabsRecommendations' => 'Finna\AjaxHandler\GetSearchTabsRecommendations',
'getSimilarRecords' => 'Finna\AjaxHandler\GetSimilarRecords',
'getUserList' => 'Finna\AjaxHandler\GetUserList',
diff --git a/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php b/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php
new file mode 100644
index 00000000000..ccdf290608e
--- /dev/null
+++ b/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php
@@ -0,0 +1,140 @@
+
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link https://vufind.org/wiki/development Wiki
+ */
+
+namespace Finna\AjaxHandler;
+
+use Laminas\Mvc\Controller\Plugin\Params;
+use VuFind\Auth\ILSAuthenticator;
+use VuFind\Db\Entity\UserEntityInterface;
+use VuFind\ILS\Connection;
+use VuFind\ILS\PaginationHelper;
+use VuFind\Session\Settings as SessionSettings;
+
+/**
+ * GetCheckoutHistory AJAX handler
+ *
+ * @category VuFind
+ * @package AJAX
+ * @author Juha Luoma
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link https://vufind.org/wiki/development Wiki
+ */
+class GetCheckoutHistory extends \VuFind\AjaxHandler\AbstractIlsAndUserAction
+{
+ protected array $cachedPatron = [];
+
+ protected array $cachedFunctionConfig = [];
+
+ /**
+ * Constructor
+ *
+ * @param SessionSettings $ss Session settings
+ * @param Connection $ils ILS connection
+ * @param ILSAuthenticator $ilsAuthenticator ILS authenticator
+ * @param ?UserEntityInterface $user Logged in user (or null)
+ * @param \VuFind\Record\Loader $recordLoader Record loader
+ * @param int $batchLimit Config specified default batch limit
+ * @param int $defaultPageSize Default page size set in config.ini
+ */
+ public function __construct(
+ SessionSettings $ss,
+ Connection $ils,
+ ILSAuthenticator $ilsAuthenticator,
+ ?UserEntityInterface $user,
+ protected \VuFind\Record\Loader $recordLoader,
+ protected int $batchLimit = 1000,
+ protected int $defaultPageSize = 50
+ ) {
+ parent::__construct($ss, $ils, $ilsAuthenticator, $user);
+ }
+
+ /**
+ * Handle a request.
+ *
+ * @param Params $params Parameter helper from controller
+ *
+ * @return array [response data, HTTP status code]
+ */
+ public function handleRequest(Params $params)
+ {
+ $this->disableSessionWrites(); // avoid session write timing bug
+ $result = $this->getCheckoutHistoryResult();
+ if ($result['success'] === false) {
+ return $this->formatResponse($result['message'], $result['status']);
+ }
+ return $this->formatResponse(['parts' => ceil(($result['function_result']['count'] ?? 1) / $this->batchLimit)]);
+ }
+
+ /**
+ * Get checkout history result for user if available
+ *
+ * @param int $page First page to get from ils
+ * @param ?int $limit Current limit for the page size or null for default
+ *
+ * @return array
+ */
+ public function getCheckoutHistoryResult(int $page = 1, ?int $limit = null): array
+ {
+ $getErrorMessage = function ($message, $status) {
+ $success = false;
+ $message = $this->translate($message);
+ return compact('success', 'message', 'status');
+ };
+ if (!$this->cachedPatron) {
+ $this->cachedPatron = $this->ilsAuthenticator->storedCatalogLogin();
+ if (!$this->user || !$this->cachedPatron) {
+ return $getErrorMessage('You must be logged in first', self::STATUS_HTTP_NEED_AUTH);
+ }
+ }
+ // Check function config
+ if (!$this->cachedFunctionConfig) {
+ $this->cachedFunctionConfig = $this->ils->checkFunction('getMyTransactionHistory', $this->cachedPatron);
+ if (false === $this->cachedFunctionConfig) {
+ return $getErrorMessage('ils_action_unavailable', self::STATUS_HTTP_UNAVAILABLE);
+ }
+ }
+ $paginationHelper = new PaginationHelper();
+ $pageOptions = $paginationHelper->getOptions(
+ $page,
+ null,
+ $limit ?? $this->defaultPageSize,
+ $this->cachedFunctionConfig
+ );
+ $result = $this->ils->getMyTransactionHistory($this->cachedPatron, $pageOptions['ilsParams']);
+ if (isset($result['success']) && !$result['success']) {
+ return $getErrorMessage('An error has occurred', self::STATUS_HTTP_ERROR);
+ }
+ return [
+ 'success' => true,
+ 'status' => 'wat',
+ 'function_result' => $result,
+ 'pageOptions' => $pageOptions,
+ ];
+ }
+}
diff --git a/module/Finna/src/Finna/AjaxHandler/AbstractIlsAndUserActionFactory.php b/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistoryFactory.php
similarity index 78%
rename from module/Finna/src/Finna/AjaxHandler/AbstractIlsAndUserActionFactory.php
rename to module/Finna/src/Finna/AjaxHandler/GetCheckoutHistoryFactory.php
index dfcb42eea5d..1c9e9ee4fae 100644
--- a/module/Finna/src/Finna/AjaxHandler/AbstractIlsAndUserActionFactory.php
+++ b/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistoryFactory.php
@@ -1,11 +1,10 @@
* @author Juha Luoma
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org/wiki/development Wiki
@@ -35,18 +33,18 @@
use Laminas\ServiceManager\Exception\ServiceNotFoundException;
use Psr\Container\ContainerExceptionInterface as ContainerException;
use Psr\Container\ContainerInterface;
+use VuFind\AjaxHandler\AbstractIlsAndUserActionFactory;
/**
- * Factory for AbstractIlsAndUserAction AJAX handlers.
+ * Factory for GetCheckoutHistory Ajax handler
*
* @category VuFind
* @package AJAX
- * @author Demian Katz
* @author Juha Luoma
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org/wiki/development Wiki
*/
-class AbstractIlsAndUserActionFactory implements \Laminas\ServiceManager\Factory\FactoryInterface
+class GetCheckoutHistoryFactory extends AbstractIlsAndUserActionFactory
{
/**
* Create an object
@@ -70,15 +68,11 @@ public function __invoke(
array $options = null
) {
$config = $container->get(\VuFind\Config\PluginManager::class)->get('config');
- return new $requestedName(
- $container->get(\VuFind\Session\Settings::class),
- $container->get(\VuFind\ILS\Connection::class),
- $container->get(\VuFind\Auth\ILSAuthenticator::class),
- $container->get(\VuFind\Auth\Manager::class)->getUserObject(),
+ $options = [
$container->get(\VuFind\Record\Loader::class),
$config->Catalog->loan_history_download_batch_limit ?? 1000,
$config->Catalog->historic_loan_page_size ?? 50,
- ...($options ?: [])
- );
+ ];
+ return parent::__invoke($container, $requestedName, $options);
}
}
diff --git a/module/Finna/src/Finna/AjaxHandler/GetTransactionHistory.php b/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistoryFile.php
similarity index 64%
rename from module/Finna/src/Finna/AjaxHandler/GetTransactionHistory.php
rename to module/Finna/src/Finna/AjaxHandler/GetCheckoutHistoryFile.php
index 9a538c83e0b..dc627458e14 100644
--- a/module/Finna/src/Finna/AjaxHandler/GetTransactionHistory.php
+++ b/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistoryFile.php
@@ -1,11 +1,11 @@
- * @author Ere Maijala
- * @author Konsta Raunio
+ * @author Juha Luoma
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org/wiki/development Wiki
*/
namespace Finna\AjaxHandler;
+use Exception;
use Laminas\Mvc\Controller\Plugin\Params;
use PhpOffice\PhpSpreadsheet\Cell\AdvancedValueBinder;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
@@ -38,25 +37,24 @@
use PhpOffice\PhpSpreadsheet\Writer\Csv;
use PhpOffice\PhpSpreadsheet\Writer\Ods;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
-use VuFind\Auth\ILSAuthenticator;
-use VuFind\Db\Entity\UserEntityInterface;
-use VuFind\ILS\Connection;
use VuFind\ILS\PaginationHelper;
-use VuFind\Session\Settings as SessionSettings;
/**
- * GetFeed AJAX handler
+ * GetCheckoutHistoryFile AJAX handler
*
* @category VuFind
* @package AJAX
- * @author Samuli Sillanpää
- * @author Ere Maijala
- * @author Konsta Raunio
+ * @author Juha Luoma
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org/wiki/development Wiki
*/
-class GetTransactionHistory extends \VuFind\AjaxHandler\AbstractIlsAndUserAction
+class GetCheckoutHistoryFile extends GetCheckoutHistory
{
+ /**
+ * Options for the file format to be requested.
+ *
+ * @var array
+ */
protected $exportFormats = [
'xlsx' => [
'mediaType' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
@@ -73,27 +71,11 @@ class GetTransactionHistory extends \VuFind\AjaxHandler\AbstractIlsAndUserAction
];
/**
- * Constructor
+ * Helper boolean for checking if this returns stream as a response
*
- * @param SessionSettings $ss Session settings
- * @param Connection $ils ILS connection
- * @param ILSAuthenticator $ilsAuthenticator ILS authenticator
- * @param ?UserEntityInterface $user Logged in user (or null)
- * @param \VuFind\Record\Loader $recordLoader Record loader
- * @param int $batchLimit Config specified default batch limit
- * @param int $defaultPageSize Default page size set in config.ini
+ * @var bool
*/
- public function __construct(
- SessionSettings $ss,
- Connection $ils,
- ILSAuthenticator $ilsAuthenticator,
- ?UserEntityInterface $user,
- protected \VuFind\Record\Loader $recordLoader,
- protected int $batchLimit = 1000,
- protected int $defaultPageSize = 50
- ) {
- parent::__construct($ss, $ils, $ilsAuthenticator, $user);
- }
+ public bool $supportsStream = true;
/**
* Handle a request.
@@ -105,74 +87,34 @@ public function __construct(
public function handleRequest(Params $params)
{
$this->disableSessionWrites(); // avoid session write timing bug
-
- $patron = $this->ilsAuthenticator->storedCatalogLogin();
- if (!$patron || !$this->user) {
- return $this->formatResponse(
- $this->translate('You must be logged in first'),
- self::STATUS_HTTP_NEED_AUTH
- );
+ $result = $this->getCheckoutHistoryResult();
+ if ($result['success'] === false) {
+ return $this->formatResponse($result['message'], $result['status']);
}
-
- $requestType = $params->fromQuery('type', 'status');
- // Check function config
- $functionConfig = $this->ils->checkFunction(
- 'getMyTransactionHistory',
- $patron
- );
- if (false === $functionConfig) {
- return $this->formatResponse(
- $this->translate('ils_action_unavailable'),
- self::STATUS_HTTP_UNAVAILABLE
- );
- }
- $paginationHelper = new PaginationHelper();
- $pageOptions = $paginationHelper->getOptions(
- 1,
- null,
- $this->defaultPageSize,
- $functionConfig
- );
-
- // Get checked out item details:
- $result = $this->ils->getMyTransactionHistory($patron, $pageOptions['ilsParams']);
- if (!($result['success'] ?? true)) {
- return $this->formatResponse(
- $this->translate('An error has occurred'),
- self::STATUS_HTTP_ERROR
- );
- }
- if ('status' === $requestType) {
- // Get amount of items in a single page
- return $this->formatResponse(
- [
- 'parts' => ceil(($result['count'] ?? 1) / 1000),
- ]
- );
- }
- if ('file' === $requestType) {
+ try {
+ $paginationHelper = new PaginationHelper();
$paginator = $paginationHelper->getPaginator(
- $pageOptions,
- $result['count'],
- $result['transactions']
+ $result['pageOptions'],
+ $result['function_result']['count'],
+ $result['function_result']['transactions']
);
// Get requested history part as a file to be downloaded
$part = $params->fromQuery('part', 1);
$fileFormat = $params->fromQuery('format', 'csv');
- $pageLimit = $paginator ? $paginator->getItemCountPerPage() : 50;
+ $pageLimit = $paginator ? $paginator->getItemCountPerPage() : $this->defaultPageSize;
$pagesCount = $paginator ? $paginator->count() : 1;
- return $this->getHistoryAsFile($patron, $part, $pageLimit, $pagesCount, $fileFormat);
+ return $this->getHistoryAsFile($part, $pageLimit, $pagesCount, $fileFormat);
+ } catch (Exception $e) {
+ return $this->formatResponse(
+ $this->translate('An error has occurred'),
+ self::STATUS_HTTP_ERROR
+ );
}
- return $this->formatResponse(
- $this->translate('An error has occurred'),
- self::STATUS_HTTP_ERROR
- );
}
/**
* Create a file for transaction history
*
- * @param array $patron Currently logged in users patron
* @param int $part Part of the transaction history to download
* @param int $limit Limit for how many transactions one fetch from ils fetches
* @param int $pagesCount Total amount of pages the user has in history
@@ -181,7 +123,6 @@ public function handleRequest(Params $params)
* @return array [fileName => name of the file, mediaType => media type, filePointer => pointer for the resource]
*/
private function getHistoryAsFile(
- array $patron,
int $part = 1,
int $limit = 50,
int $pagesCount = 1,
@@ -196,16 +137,21 @@ private function getHistoryAsFile(
$firstPageToFetch += ($pagesToFetch * ($part - 1));
$lastPageToFetch += min(($pagesToFetch * $part) - 1, $pagesCount);
}
- $tmp = fopen('php://temp/maxmemory:' . (5 * 1024 * 1024), 'r+');
+ $tmpPath = 'php://temp/maxmemory:' . (5 * 1024 * 1024);
+ $tmp = fopen($tmpPath, 'r+');
$transactions = [];
for ($i = $firstPageToFetch; $i <= $lastPageToFetch; $i++) {
- $result = $this->ils->getMyTransactionHistory($patron, ['page' => $i, 'limit' => $limit]);
+ $result = $this->getCheckoutHistoryResult($i, $limit);
+ if ($result['success'] === false) {
+ fclose($tmp);
+ return $this->formatResponse($result['message'], $result['status']);
+ }
// Break if no transactions found
- if (empty($result['transactions'])) {
+ if (empty($result['function_result']['transactions'])) {
break;
}
- $transactions = [...$transactions, ...$result['transactions']];
+ $transactions = [...$transactions, ...$result['function_result']['transactions']];
}
$ids = [];
foreach ($transactions as $current) {
@@ -214,7 +160,6 @@ private function getHistoryAsFile(
$ids[] = compact('id', 'source');
}
$records = $this->recordLoader->loadBatch($ids, true);
-
$header = [
$this->translate('Title'),
$this->translate('Format'),
@@ -226,7 +171,6 @@ private function getHistoryAsFile(
$this->translate('Return Date'),
$this->translate('Due Date'),
];
-
$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
$worksheet->fromArray($header);
diff --git a/module/Finna/src/Finna/Controller/AjaxController.php b/module/Finna/src/Finna/Controller/AjaxController.php
index 82ade0ebb1c..2a05abc5525 100644
--- a/module/Finna/src/Finna/Controller/AjaxController.php
+++ b/module/Finna/src/Finna/Controller/AjaxController.php
@@ -56,29 +56,7 @@ public function onlinePaymentNotifyAction()
}
/**
- * Format the content of the AJAX response based on the response type.
- *
- * @param string $type Content-type of output
- * @param mixed $data The response data
- * @param int $httpCode A custom HTTP Status Code
- *
- * @return string
- * @throws \Exception
- */
- protected function formatContent($type, $data, $httpCode)
- {
- if ($type !== 'file_type_content') {
- return parent::formatContent($type, $data, $httpCode);
- }
- if ($httpCode === 200) {
- return $this->getFileResponse($data);
- } else {
- return parent::formatContent('text/plain', $data, $httpCode);
- }
- }
-
- /**
- * Get a file download
+ * Handle a file download with AJAX call
*
* @return \Laminas\Http\Response
*/
@@ -88,7 +66,30 @@ public function fileAction()
if (!$method) {
return $this->getAjaxResponse('text/plain', ['error' => 'Parameter "method" missing'], 400);
}
- return $this->callAjaxMethod($method, 'file_type_content');
+ // Check the AJAX handler plugin manager for the method.
+ if (!$this->ajaxManager) {
+ throw new \Exception('AJAX Handler Plugin Manager missing.');
+ }
+ if ($this->ajaxManager->has($method)) {
+ try {
+ $handler = $this->ajaxManager->get($method);
+ if ($handler->supportsStream ?? false) {
+ [$data, $status] = $handler->handleRequest($this->params());
+ if ($status === 200) {
+ return $this->getFileResponse($data);
+ }
+ }
+ } catch (\Exception $e) {
+ return $this->getExceptionResponse('text/plain', $e);
+ }
+ }
+
+ // If we got this far, we can't handle the requested method:
+ return $this->getAjaxResponse(
+ 'text/plain',
+ $this->translate('Invalid Method'),
+ \VuFind\AjaxHandler\AjaxHandlerInterface::STATUS_HTTP_BAD_REQUEST
+ );
}
/**
@@ -105,6 +106,8 @@ protected function getFileResponse($data)
$headers = $response->getHeaders();
$headers->addHeaderLine('Content-type', $data['mediaType']);
$headers->addHeaderLine('Content-Disposition', 'attachment; filename="' . $data['fileName'] . '"');
- return stream_get_contents($data['filePointer']);
+ $headers->addHeaderLine('Cache-Control', 'no-cache, must-revalidate');
+ $headers->addHeaderLine('Expires', 'Mon, 26 Jul 1997 05:00:00 GMT');
+ return $response->setContent(stream_get_contents($data['filePointer']));
}
}
diff --git a/module/Finna/src/Finna/Controller/MyResearchController.php b/module/Finna/src/Finna/Controller/MyResearchController.php
index 4f2237926cf..9df1fe545c5 100644
--- a/module/Finna/src/Finna/Controller/MyResearchController.php
+++ b/module/Finna/src/Finna/Controller/MyResearchController.php
@@ -1313,7 +1313,7 @@ public function importAction()
* Download historic loans
*
* @return mixed
- * @deprecated Use AjaxHandler/GetTransactionHistory
+ * @deprecated Use AjaxHandler/GetCheckoutHistory
*/
public function downloadLoanHistoryAction()
{
diff --git a/themes/finna2/js/finna-transaction-history.js b/themes/finna2/js/finna-checkout-history.js
similarity index 54%
rename from themes/finna2/js/finna-transaction-history.js
rename to themes/finna2/js/finna-checkout-history.js
index 212d961c8f6..2fe438a7f38 100644
--- a/themes/finna2/js/finna-transaction-history.js
+++ b/themes/finna2/js/finna-checkout-history.js
@@ -1,7 +1,5 @@
/*global finna, VuFind */
-finna.transactionHistory = (function transactionHistory() {
-
- const historyButtonSelector = 'div.js-download-loan-history';
+finna.checkoutHistory = (function checkoutHistory() {
const toggleButtonSelector = 'button.js-history-toggle';
@@ -15,13 +13,9 @@ finna.transactionHistory = (function transactionHistory() {
function setNextPage(element) {
let currentPart = +element.dataset.currentPart;
let lastPart = +element.dataset.lastPart;
- if (currentPart < lastPart) {
- currentPart++;
- }
- element.dataset.currentPart = currentPart;
+ element.dataset.currentPart = Math.min(++currentPart, lastPart);
}
-
/**
* Sets the buttons text content to match for the next page to be downloaded if clicked.
* @param {HTMLButtonElement} element Button element to be clicked to download history
@@ -34,48 +28,62 @@ finna.transactionHistory = (function transactionHistory() {
toggleButton.append(VuFind.icon('show-more', {}, true));
}
+
+ /**
+ * Display a spinner inside toggle button
+ * @param {HTMLElement} element Element containing toggleButton
+ */
+ function displaySpinner(element)
+ {
+ const toggleButton = element.querySelector(toggleButtonSelector);
+ const spinnerElement = VuFind.icon('spinner', {}, true);
+ toggleButton.replaceChildren(spinnerElement, ` ${VuFind.translate('loading_ellipsis')}`);
+ }
+
/**
- * Request part of a transaction history to download
- * @param {HTMLElement} element Parent element for transaction history downloading
+ * Request part of a checkout history to download
+ * @param {HTMLElement} element Parent element for checkout history downloading
* @param {string} formatButton Clicked button containing format specific data
*/
- function getTransactionHistoryPart(element, formatButton)
+ function getCheckoutHistoryPart(element, formatButton)
{
+ displaySpinner(element);
const part = element.dataset.currentPart;
const format = formatButton.dataset.format;
- const searchParams = new URLSearchParams({method: "getTransactionHistory", part, format, type: "file"});
+ const searchParams = new URLSearchParams({method: "getCheckoutHistoryFile", part, format});
let filename;
- fetch (`${VuFind.path}/AJAX/FILE?${searchParams}`).then(response => {
- if (!response.ok) {
- throw new Error('');
- }
- const header = response.headers.get('Content-Disposition');
- const parts = header.split(';');
- filename = parts[1].split('=')[1].replaceAll("\"", "");
-
- return response.blob();
- }).then((blob) => {
- var url = window.URL.createObjectURL(blob);
- var a = document.createElement('a');
- a.href = url;
- a.download = filename;
- document.body.appendChild(a); // we need to append the element to the dom -> otherwise it will not work in firefox
- a.click();
- a.remove();
- setNextPage(element);
- syncButtonText(element);
- }).catch((reason) => {
- console.warn(reason);
- });
+ fetch (`${VuFind.path}/AJAX/FILE?${searchParams}`)
+ .then(response => {
+ if (!response.ok) {
+ throw new Error('');
+ }
+ const header = response.headers.get('Content-Disposition');
+ const parts = header.split(';');
+ filename = parts[1].split('=')[1].replaceAll("\"", "");
+ return response.blob();
+ }).then((blob) => {
+ const url = window.URL.createObjectURL(blob);
+ var a = document.createElement('a');
+ a.href = url;
+ a.download = filename;
+ document.body.appendChild(a); // we need to append the element to the dom -> otherwise it will not work in firefox
+ a.click();
+ a.remove();
+ setNextPage(element);
+ syncButtonText(element);
+ }).catch((reason) => {
+ console.warn(reason);
+ syncButtonText(element);
+ });
}
/**
- * Initializes a button to allow for loading loan history in chunks.
+ * Initializes an element containing format buttons to allow for loading checkout history in batches.
* @param {HTMLButtonElement} element Button element to be clicked to download history
* @returns {void}
*/
- function initButton(element) {
- fetch (`${VuFind.path}/AJAX/JSON?method=getTransactionHistory&type=status`)
+ function init(element) {
+ fetch (`${VuFind.path}/AJAX/JSON?method=getCheckoutHistory&type=status`)
.then(response => {
if (!response.ok) {
throw new Error('');
@@ -94,7 +102,7 @@ finna.transactionHistory = (function transactionHistory() {
formatButtons.forEach(formatButton => {
formatButton.addEventListener('click', (e) => {
e.preventDefault();
- getTransactionHistoryPart(element, formatButton);
+ getCheckoutHistoryPart(element, formatButton);
});
});
}
@@ -104,12 +112,6 @@ finna.transactionHistory = (function transactionHistory() {
});
}
- /**
- * Initialize buttons to handle downloading transaction history
- */
- function init() {
- document.querySelectorAll(historyButtonSelector).forEach(el => { initButton(el); });
- }
return {
init: init
};
diff --git a/themes/finna2/js/finna.js b/themes/finna2/js/finna.js
index 034ad6ba1ba..5ab6a4c2dba 100644
--- a/themes/finna2/js/finna.js
+++ b/themes/finna2/js/finna.js
@@ -44,7 +44,6 @@ var finna = (function finnaModule() {
'mdEditable',
'a11y',
'finnaDatepicker',
- 'transactionHistory',
'reservationList',
];
diff --git a/themes/finna2/templates/checkouts/history.phtml b/themes/finna2/templates/checkouts/history.phtml
index 70f1e6990fe..7b95e7c7cb3 100644
--- a/themes/finna2/templates/checkouts/history.phtml
+++ b/themes/finna2/templates/checkouts/history.phtml
@@ -212,4 +212,14 @@
+ {
+ finna.checkoutHistory.init(document.querySelector('div.js-download-loan-history'));
+ });
+ JS;
+
+echo $this->inlineScript()->appendScript($js);
+?>
diff --git a/themes/finna2/theme.config.php b/themes/finna2/theme.config.php
index 8b1b5482dbe..833608fbeab 100644
--- a/themes/finna2/theme.config.php
+++ b/themes/finna2/theme.config.php
@@ -267,7 +267,7 @@
'finna-select-a11y.js',
'finna-a11y.js',
'finna-datepicker.js',
- 'finna-transaction-history.js',
+ 'finna-checkout-history.js',
'finna-reservation-list.js',
'components/finna-bazaar-browse-bar.js',
'components/finna-md-editable.js',
From 39061abedff96c4e7fc68e7cf91ce3b894b5377f Mon Sep 17 00:00:00 2001
From: Juha Luoma <33253757+LuomaJuha@users.noreply.github.com>
Date: Wed, 15 Jan 2025 19:39:55 +0200
Subject: [PATCH 16/24] Added comments
---
.../Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php b/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php
index ccdf290608e..a1766294f5d 100644
--- a/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php
+++ b/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php
@@ -47,8 +47,18 @@
*/
class GetCheckoutHistory extends \VuFind\AjaxHandler\AbstractIlsAndUserAction
{
+ /**
+ * Cache for patron
+ *
+ * @var array
+ */
protected array $cachedPatron = [];
+ /**
+ * Cache for function config.
+ *
+ * @var array
+ */
protected array $cachedFunctionConfig = [];
/**
From 9ba8d20d5af9be25c0261f47bd3f17f8fe04c7ef Mon Sep 17 00:00:00 2001
From: Juha Luoma <33253757+LuomaJuha@users.noreply.github.com>
Date: Wed, 15 Jan 2025 19:41:13 +0200
Subject: [PATCH 17/24] Removed unused parameter type
---
themes/finna2/js/finna-checkout-history.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/themes/finna2/js/finna-checkout-history.js b/themes/finna2/js/finna-checkout-history.js
index 2fe438a7f38..7f0c6c110b9 100644
--- a/themes/finna2/js/finna-checkout-history.js
+++ b/themes/finna2/js/finna-checkout-history.js
@@ -83,7 +83,7 @@ finna.checkoutHistory = (function checkoutHistory() {
* @returns {void}
*/
function init(element) {
- fetch (`${VuFind.path}/AJAX/JSON?method=getCheckoutHistory&type=status`)
+ fetch (`${VuFind.path}/AJAX/JSON?method=getCheckoutHistory`)
.then(response => {
if (!response.ok) {
throw new Error('');
From 6ca8bb4a9169e2d94a8753c84def8d15e2bb3d3e Mon Sep 17 00:00:00 2001
From: Juha Luoma <33253757+LuomaJuha@users.noreply.github.com>
Date: Wed, 15 Jan 2025 19:42:52 +0200
Subject: [PATCH 18/24] Adjusted js comments
---
themes/finna2/js/finna-checkout-history.js | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/themes/finna2/js/finna-checkout-history.js b/themes/finna2/js/finna-checkout-history.js
index 7f0c6c110b9..86419ae5864 100644
--- a/themes/finna2/js/finna-checkout-history.js
+++ b/themes/finna2/js/finna-checkout-history.js
@@ -7,7 +7,7 @@ finna.checkoutHistory = (function checkoutHistory() {
/**
* Calculates the current page for the button limited by the last possible page to be downloaded.
- * @param {HTMLButtonElement} element Button element to be clicked to download history
+ * @param {HTMLButtonElement} element Element containing toggleButton
* @returns {void}
*/
function setNextPage(element) {
@@ -18,7 +18,7 @@ finna.checkoutHistory = (function checkoutHistory() {
/**
* Sets the buttons text content to match for the next page to be downloaded if clicked.
- * @param {HTMLButtonElement} element Button element to be clicked to download history
+ * @param {HTMLButtonElement} element Element containing toggleButton
* @returns {void}
*/
function syncButtonText(element) {
@@ -28,7 +28,6 @@ finna.checkoutHistory = (function checkoutHistory() {
toggleButton.append(VuFind.icon('show-more', {}, true));
}
-
/**
* Display a spinner inside toggle button
* @param {HTMLElement} element Element containing toggleButton
@@ -79,7 +78,7 @@ finna.checkoutHistory = (function checkoutHistory() {
/**
* Initializes an element containing format buttons to allow for loading checkout history in batches.
- * @param {HTMLButtonElement} element Button element to be clicked to download history
+ * @param {HTMLButtonElement} element Element to be initialized
* @returns {void}
*/
function init(element) {
From 6931dbf417c8f6282ade1deaf783dddd06f84346 Mon Sep 17 00:00:00 2001
From: Juha Luoma <33253757+LuomaJuha@users.noreply.github.com>
Date: Thu, 16 Jan 2025 11:19:32 +0200
Subject: [PATCH 19/24] Removed test variable..
---
module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php | 1 -
1 file changed, 1 deletion(-)
diff --git a/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php b/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php
index a1766294f5d..31950eb4994 100644
--- a/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php
+++ b/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php
@@ -142,7 +142,6 @@ public function getCheckoutHistoryResult(int $page = 1, ?int $limit = null): arr
}
return [
'success' => true,
- 'status' => 'wat',
'function_result' => $result,
'pageOptions' => $pageOptions,
];
From 1d742b51f28efbfa538e6fbedaed6a3ec233c642 Mon Sep 17 00:00:00 2001
From: Juha Luoma <33253757+LuomaJuha@users.noreply.github.com>
Date: Thu, 16 Jan 2025 12:08:16 +0200
Subject: [PATCH 20/24] Adjusted to calculate history properly
---
.../Finna/AjaxHandler/GetCheckoutHistory.php | 33 ++++++++++++++++++-
.../AjaxHandler/GetCheckoutHistoryFile.php | 22 ++++++-------
2 files changed, 43 insertions(+), 12 deletions(-)
diff --git a/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php b/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php
index 31950eb4994..de365668fce 100644
--- a/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php
+++ b/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php
@@ -81,6 +81,9 @@ public function __construct(
protected int $batchLimit = 1000,
protected int $defaultPageSize = 50
) {
+ if ($this->batchLimit < $defaultPageSize) {
+ $this->batchLimit = $defaultPageSize;
+ }
parent::__construct($ss, $ils, $ilsAuthenticator, $user);
}
@@ -98,7 +101,35 @@ public function handleRequest(Params $params)
if ($result['success'] === false) {
return $this->formatResponse($result['message'], $result['status']);
}
- return $this->formatResponse(['parts' => ceil(($result['function_result']['count'] ?? 1) / $this->batchLimit)]);
+ $calculatedResults = $this->calculateLimitsFromResult($result);
+ return $this->formatResponse(['parts' => $calculatedResults['parts']]);
+ }
+
+ /**
+ * Calculate limits used to fetch data from the results obtained from getCheckoutHistoryResult.
+ *
+ * @param array $result Checkout history result
+ *
+ * @return array
+ */
+ public function calculateLimitsFromResult(array $result): array
+ {
+ $resultCount = $result['function_result']['count'] ?? 1;
+ $paginationHelper = new PaginationHelper();
+ $paginator = $paginationHelper->getPaginator(
+ $result['pageOptions'],
+ $result['function_result']['count'],
+ $result['function_result']['transactions']
+ );
+ $pageLimit = $paginator ? $paginator->getItemCountPerPage() : $this->defaultPageSize;
+ $parts = $pageLimit > $this->batchLimit
+ ? floor($resultCount / $this->batchLimit)
+ : ceil($resultCount / $this->batchLimit);
+ return [
+ 'pageLimit' => $paginator ? $paginator->getItemCountPerPage() : $this->defaultPageSize,
+ 'pageCount' => $paginator ? $paginator->count() : 1,
+ 'parts' => $parts,
+ ];
}
/**
diff --git a/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistoryFile.php b/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistoryFile.php
index dc627458e14..57cc47f85e9 100644
--- a/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistoryFile.php
+++ b/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistoryFile.php
@@ -37,7 +37,6 @@
use PhpOffice\PhpSpreadsheet\Writer\Csv;
use PhpOffice\PhpSpreadsheet\Writer\Ods;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
-use VuFind\ILS\PaginationHelper;
/**
* GetCheckoutHistoryFile AJAX handler
@@ -92,18 +91,16 @@ public function handleRequest(Params $params)
return $this->formatResponse($result['message'], $result['status']);
}
try {
- $paginationHelper = new PaginationHelper();
- $paginator = $paginationHelper->getPaginator(
- $result['pageOptions'],
- $result['function_result']['count'],
- $result['function_result']['transactions']
- );
// Get requested history part as a file to be downloaded
$part = $params->fromQuery('part', 1);
$fileFormat = $params->fromQuery('format', 'csv');
- $pageLimit = $paginator ? $paginator->getItemCountPerPage() : $this->defaultPageSize;
- $pagesCount = $paginator ? $paginator->count() : 1;
- return $this->getHistoryAsFile($part, $pageLimit, $pagesCount, $fileFormat);
+ $calculatedResults = $this->calculateLimitsFromResult($result);
+ return $this->getHistoryAsFile(
+ $part,
+ $calculatedResults['pageLimit'],
+ $calculatedResults['pageCount'],
+ $fileFormat
+ );
} catch (Exception $e) {
return $this->formatResponse(
$this->translate('An error has occurred'),
@@ -213,7 +210,10 @@ private function getHistoryAsFile(
}
$writer = new $this->exportFormats[$fileFormat]['writer']($spreadsheet);
$writer->save($tmp);
- $fileName = implode('-', ['finna-loan-history-pages', $firstPageToFetch, $lastPageToFetch]);
+ $fileName = 'finna-loan-history-parts-' . $firstPageToFetch;
+ if ($firstPageToFetch !== $lastPageToFetch) {
+ $fileName .= '-' . $lastPageToFetch;
+ }
$fileName .= ".$fileFormat";
rewind($tmp);
From 6125ab80abf2f1eb23f42b987377212b90bbf456 Mon Sep 17 00:00:00 2001
From: Juha Luoma <33253757+LuomaJuha@users.noreply.github.com>
Date: Thu, 16 Jan 2025 14:34:42 +0200
Subject: [PATCH 21/24] Added test for GetCheckoutHistory
---
.../Finna/AjaxHandler/GetCheckoutHistory.php | 5 +-
.../AjaxHandler/GetCheckoutHistoryTest.php | 281 ++++++++++++++++++
2 files changed, 284 insertions(+), 2 deletions(-)
create mode 100644 module/Finna/tests/unit-tests/src/FinnaTest/AjaxHandler/GetCheckoutHistoryTest.php
diff --git a/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php b/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php
index de365668fce..340d5221578 100644
--- a/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php
+++ b/module/Finna/src/Finna/AjaxHandler/GetCheckoutHistory.php
@@ -148,10 +148,11 @@ public function getCheckoutHistoryResult(int $page = 1, ?int $limit = null): arr
return compact('success', 'message', 'status');
};
if (!$this->cachedPatron) {
- $this->cachedPatron = $this->ilsAuthenticator->storedCatalogLogin();
- if (!$this->user || !$this->cachedPatron) {
+ $patron = $this->ilsAuthenticator->storedCatalogLogin();
+ if (!$this->user || !$patron) {
return $getErrorMessage('You must be logged in first', self::STATUS_HTTP_NEED_AUTH);
}
+ $this->cachedPatron = $patron;
}
// Check function config
if (!$this->cachedFunctionConfig) {
diff --git a/module/Finna/tests/unit-tests/src/FinnaTest/AjaxHandler/GetCheckoutHistoryTest.php b/module/Finna/tests/unit-tests/src/FinnaTest/AjaxHandler/GetCheckoutHistoryTest.php
new file mode 100644
index 00000000000..63250741fab
--- /dev/null
+++ b/module/Finna/tests/unit-tests/src/FinnaTest/AjaxHandler/GetCheckoutHistoryTest.php
@@ -0,0 +1,281 @@
+
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link https://vufind.org Main Page
+ */
+
+namespace VuFindTest\AjaxHandler;
+
+use Finna\AjaxHandler\GetCheckoutHistory;
+use Finna\AjaxHandler\GetCheckoutHistoryFactory;
+use Laminas\Config\Config;
+use VuFind\Auth\ILSAuthenticator;
+use VuFind\Auth\Manager;
+use VuFind\Db\Entity\UserEntityInterface;
+use VuFind\ILS\Connection;
+
+/**
+ * GetCheckoutHistory test class.
+ *
+ * @category VuFind
+ * @package Tests
+ * @author Juha Luoma