diff --git a/module/VuFind/config/module.config.php b/module/VuFind/config/module.config.php index e70cda5b0b04f0cd990b31eb1fa7a65ba5287a49..d5b271c12e6db7eddb0e34474b613eef0361181d 100644 --- a/module/VuFind/config/module.config.php +++ b/module/VuFind/config/module.config.php @@ -105,7 +105,7 @@ $config = [ ], 'controllers' => [ 'factories' => [ - 'VuFind\Controller\AjaxController' => 'VuFind\Controller\AbstractBaseFactory', + 'VuFind\Controller\AjaxController' => 'VuFind\Controller\AjaxControllerFactory', 'VuFind\Controller\AlphabrowseController' => 'VuFind\Controller\AbstractBaseFactory', 'VuFind\Controller\AuthorController' => 'VuFind\Controller\AbstractBaseFactory', 'VuFind\Controller\AuthorityController' => 'VuFind\Controller\AbstractBaseFactory', @@ -280,6 +280,7 @@ $config = [ 'allow_override' => true, 'factories' => [ 'ProxyManager\Configuration' => 'VuFind\Service\Factory::getProxyConfig', + 'VuFind\AjaxHandler\PluginManager' => 'VuFind\ServiceManager\AbstractPluginManagerFactory', 'VuFind\Auth\ILSAuthenticator' => 'VuFind\Auth\ILSAuthenticatorFactory', 'VuFind\Auth\Manager' => 'VuFind\Auth\ManagerFactory', 'VuFind\Auth\PluginManager' => 'VuFind\ServiceManager\AbstractPluginManagerFactory', @@ -458,6 +459,7 @@ $config = [ // This section contains service manager configurations for all VuFind // pluggable components: 'plugin_managers' => [ + 'ajaxhandler' => [ /* see VuFind\AjaxHandler\PluginManager for defaults */ ], 'auth' => [ /* see VuFind\Auth\PluginManager for defaults */ ], 'autocomplete' => [ /* see VuFind\Autocomplete\PluginManager for defaults */ ], 'channelprovider' => [ /* see VuFind\ChannelProvider\PluginManager for defaults */ ], diff --git a/module/VuFind/src/VuFind/AjaxHandler/AbstractBase.php b/module/VuFind/src/VuFind/AjaxHandler/AbstractBase.php new file mode 100644 index 0000000000000000000000000000000000000000..3122fdc2f9c25210457f51562915c5806001d584 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/AbstractBase.php @@ -0,0 +1,85 @@ +<?php +/** + * Abstract base AJAX handler + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use VuFind\Session\Settings as SessionSettings; + +/** + * Abstract base AJAX handler + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +abstract class AbstractBase implements AjaxHandlerInterface +{ + /** + * Session settings + * + * @var SessionSettings + */ + protected $sessionSettings = null; + + /** + * Prevent session writes -- this is designed to be called prior to time- + * consuming AJAX operations to help reduce the odds of a timing-related bug + * that causes the wrong version of session data to be written to disk (see + * VUFIND-716 for more details). + * + * @return void + */ + protected function disableSessionWrites() + { + if (null === $this->sessionSettings) { + throw new \Exception('Session settings object missing.'); + } + $this->sessionSettings->disableWrite(); + } + + /** + * Format a response array. + * + * @param mixed $response Response data + * @param string $status Internal status code (see constants in interface; + * defaults to OK) + * @param int $httpCode HTTP status code (omit for default) + * + * @return array + */ + protected function formatResponse($response, $status = self::STATUS_OK, + $httpCode = null + ) { + $arr = [$response, $status]; + if ($httpCode !== null) { + $arr[] = $httpCode; + } + return $arr; + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/AbstractIlsAndUserAction.php b/module/VuFind/src/VuFind/AjaxHandler/AbstractIlsAndUserAction.php new file mode 100644 index 0000000000000000000000000000000000000000..9692e2964239ee45c81ecb5eaa1cf37c6716bc7c --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/AbstractIlsAndUserAction.php @@ -0,0 +1,87 @@ +<?php +/** + * Abstract base class for handlers depending on the ILS and a logged-in user. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use VuFind\Auth\ILSAuthenticator; +use VuFind\Db\Row\User; +use VuFind\I18n\Translator\TranslatorAwareInterface; +use VuFind\ILS\Connection; +use VuFind\Session\Settings as SessionSettings; + +/** + * Abstract base class for handlers depending on the ILS and a logged-in user. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +abstract class AbstractIlsAndUserAction extends AbstractBase + implements TranslatorAwareInterface +{ + use \VuFind\I18n\Translator\TranslatorAwareTrait; + + /** + * ILS connection + * + * @var Connection + */ + protected $ils; + + /** + * ILS authenticator + * + * @var ILSAuthenticator + */ + protected $ilsAuthenticator; + + /** + * Logged in user (or false) + * + * @var User|bool + */ + protected $user; + + /** + * Constructor + * + * @param SessionSettings $ss Session settings + * @param Connection $ils ILS connection + * @param ILSAuthenticator $ilsAuthenticator ILS authenticator + * @param User|bool $user Logged in user (or false) + */ + public function __construct(SessionSettings $ss, Connection $ils, + ILSAuthenticator $ilsAuthenticator, $user + ) { + $this->sessionSettings = $ss; + $this->ils = $ils; + $this->ilsAuthenticator = $ilsAuthenticator; + $this->user = $user; + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/AbstractIlsAndUserActionFactory.php b/module/VuFind/src/VuFind/AjaxHandler/AbstractIlsAndUserActionFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..aa6b52517bd9f5dce9b1c8ea6b3ed00e9dc8e612 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/AbstractIlsAndUserActionFactory.php @@ -0,0 +1,73 @@ +<?php +/** + * Factory for AbstractIlsAndUserAction AJAX handlers. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Interop\Container\ContainerInterface; + +/** + * Factory for AbstractIlsAndUserAction AJAX handlers. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class AbstractIlsAndUserActionFactory + implements \Zend\ServiceManager\Factory\FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options passed to factory.'); + } + return new $requestedName( + $container->get('VuFind\Session\Settings'), + $container->get('VuFind\ILS\Connection'), + $container->get('VuFind\Auth\ILSAuthenticator'), + $container->get('VuFind\Auth\Manager')->isLoggedIn() + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/AjaxHandlerInterface.php b/module/VuFind/src/VuFind/AjaxHandler/AjaxHandlerInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..70eff2f6e8e17a610e351db8d3132240c09c38a1 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/AjaxHandlerInterface.php @@ -0,0 +1,56 @@ +<?php +/** + * AJAX handler interface + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Zend\Mvc\Controller\Plugin\Params; + +/** + * AJAX handler interface + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +interface AjaxHandlerInterface +{ + // define some status constants + const STATUS_OK = 'OK'; // good + const STATUS_ERROR = 'ERROR'; // bad + const STATUS_NEED_AUTH = 'NEED_AUTH'; // must login first + + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + */ + public function handleRequest(Params $params); +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/CheckRequestIsValid.php b/module/VuFind/src/VuFind/AjaxHandler/CheckRequestIsValid.php new file mode 100644 index 0000000000000000000000000000000000000000..88fdc30634f72a39ed14bf2965db745a2860fd7c --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/CheckRequestIsValid.php @@ -0,0 +1,145 @@ +<?php +/** + * "Check Request is Valid" AJAX handler + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Zend\Mvc\Controller\Plugin\Params; + +/** + * "Check Request is Valid" AJAX handler + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class CheckRequestIsValid extends AbstractIlsAndUserAction +{ + /** + * Status messages + * + * @var array + */ + protected $statuses = [ + 'ILLRequest' => [ + 'success' => 'ill_request_place_text', + 'failure' => 'ill_request_error_blocked', + ], + 'StorageRetrievalRequest' => [ + 'success' => 'storage_retrieval_request_place_text', + 'failure' => 'storage_retrieval_request_error_blocked', + ], + ]; + + /** + * Given a request type and a boolean success status, return an appropriate + * message. + * + * @param string $requestType Type of request being made + * @param bool $results Result status + * + * @return string + */ + protected function getStatusMessage($requestType, $results) + { + // If successful, return success message: + if ($results) { + return isset($this->statuses[$requestType]['success']) + ? $this->statuses[$requestType]['success'] + : 'request_place_text'; + } + // If unsuccessful, return failure message: + return isset($this->statuses[$requestType]['failure']) + ? $this->statuses[$requestType]['failure'] + : 'hold_error_blocked'; + } + + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + */ + public function handleRequest(Params $params) + { + $this->disableSessionWrites(); // avoid session write timing bug + $id = $params->fromQuery('id'); + $data = $params->fromQuery('data'); + $requestType = $params->fromQuery('requestType'); + if (empty($id) || empty($data)) { + return $this->formatResponse( + $this->translate('bulk_error_missing'), + self::STATUS_ERROR, + 400 + ); + } + // check if user is logged in + if (!$this->user) { + return $this->formatResponse( + $this->translate('You must be logged in first'), + self::STATUS_NEED_AUTH, + 401 + ); + } + + try { + $patron = $this->ilsAuthenticator->storedCatalogLogin(); + if ($patron) { + switch ($requestType) { + case 'ILLRequest': + $results = $this->ils + ->checkILLRequestIsValid($id, $data, $patron); + break; + case 'StorageRetrievalRequest': + $results = $this->ils + ->checkStorageRetrievalRequestIsValid($id, $data, $patron); + break; + default: + $results = $this->ils->checkRequestIsValid($id, $data, $patron); + break; + } + if (is_array($results)) { + $msg = $results['status']; + $results = $results['valid']; + } else { + $msg = $this->getStatusMessage($requestType, $results); + } + return $this->formatResponse( + ['status' => $results, 'msg' => $this->translate($msg)] + ); + } + } catch (\Exception $e) { + // Do nothing -- just fail through to the error message below. + } + + return $this->formatResponse( + $this->translate('An error has occurred'), self::STATUS_ERROR, 500 + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/CommentRecord.php b/module/VuFind/src/VuFind/AjaxHandler/CommentRecord.php new file mode 100644 index 0000000000000000000000000000000000000000..496cf84c74ac1b765f06cd36955bec5197a187d5 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/CommentRecord.php @@ -0,0 +1,159 @@ +<?php +/** + * AJAX handler to comment on a record. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use VuFind\Controller\Plugin\Recaptcha; +use VuFind\Db\Row\User; +use VuFind\Db\Table\Resource; +use VuFind\I18n\Translator\TranslatorAwareInterface; +use Zend\Mvc\Controller\Plugin\Params; + +/** + * AJAX handler to comment on a record. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class CommentRecord extends AbstractBase implements TranslatorAwareInterface +{ + use \VuFind\I18n\Translator\TranslatorAwareTrait; + + /** + * Resource database table + * + * @var Resource + */ + protected $table; + + /** + * Recaptcha controller plugin + * + * @var Recaptcha + */ + protected $recaptcha; + + /** + * Logged in user (or false) + * + * @var User|bool + */ + protected $user; + + /** + * Are comments enabled? + * + * @var bool + */ + protected $enabled; + + /** + * Constructor + * + * @param Resource $table Resource database table + * @param Recaptcha $recaptcha Recaptcha controller plugin + * @param User|bool $user Logged in user (or false) + * @param bool $enabled Are comments enabled? + */ + public function __construct(Resource $table, Recaptcha $recaptcha, $user, + $enabled = true + ) { + $this->table = $table; + $this->recaptcha = $recaptcha; + $this->user = $user; + $this->enabled = $enabled; + } + + /** + * Is CAPTCHA valid? (Also returns true if CAPTCHA is disabled). + * + * @param Params $params Parameter helper from controller + * + * @return bool + */ + protected function checkCaptcha(Params $params) + { + // Not enabled? Report success! + if (!$this->recaptcha->active('userComments')) { + return true; + } + $this->recaptcha->setErrorMode('none'); + return $this->recaptcha->validate(); + } + + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + */ + public function handleRequest(Params $params) + { + // Make sure comments are enabled: + if (!$this->enabled) { + return $this->formatResponse( + $this->translate('Comments disabled'), + self::STATUS_ERROR, + 403 + ); + } + + if ($this->user === false) { + return $this->formatResponse( + $this->translate('You must be logged in first'), + self::STATUS_NEED_AUTH, + 401 + ); + } + + $id = $params->fromPost('id'); + $source = $params->fromPost('source', DEFAULT_SEARCH_BACKEND); + $comment = $params->fromPost('comment'); + if (empty($id) || empty($comment)) { + return $this->formatResponse( + $this->translate('bulk_error_missing'), + self::STATUS_ERROR, + 400 + ); + } + + if (!$this->checkCaptcha($params)) { + return $this->formatResponse( + $this->translate('recaptcha_not_passed'), + self::STATUS_ERROR, + 403 + ); + } + + $resource = $this->table->findResource($id, $source); + return $this->formatResponse($resource->addComment($comment, $this->user)); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/CommentRecordFactory.php b/module/VuFind/src/VuFind/AjaxHandler/CommentRecordFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..35a9ff1cec087c12efc368596c06b5c3f7fbc285 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/CommentRecordFactory.php @@ -0,0 +1,75 @@ +<?php +/** + * Factory for CommentRecord AJAX handler. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Interop\Container\ContainerInterface; + +/** + * Factory for CommentRecord AJAX handler. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class CommentRecordFactory implements \Zend\ServiceManager\Factory\FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options passed to factory.'); + } + $tablePluginManager = $container->get('VuFind\Db\Table\PluginManager'); + $controllerPluginManager = $container->get('ControllerPluginManager'); + $capabilities = $container->get('VuFind\Config\AccountCapabilities'); + return new $requestedName( + $tablePluginManager->get('VuFind\Db\Table\Resource'), + $controllerPluginManager->get('VuFind\Controller\Plugin\Recaptcha'), + $container->get('VuFind\Auth\Manager')->isLoggedIn(), + $capabilities->getCommentSetting() !== 'disabled' + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/DeleteRecordComment.php b/module/VuFind/src/VuFind/AjaxHandler/DeleteRecordComment.php new file mode 100644 index 0000000000000000000000000000000000000000..327d8cd8b3fc6795c212c9dc99b65d96975edd9a --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/DeleteRecordComment.php @@ -0,0 +1,127 @@ +<?php +/** + * AJAX handler to delete a comment on a record. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use VuFind\Db\Row\User; +use VuFind\Db\Table\Comments; +use VuFind\I18n\Translator\TranslatorAwareInterface; +use Zend\Mvc\Controller\Plugin\Params; + +/** + * AJAX handler to delete a comment on a record. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class DeleteRecordComment extends AbstractBase implements TranslatorAwareInterface +{ + use \VuFind\I18n\Translator\TranslatorAwareTrait; + + /** + * Comments database table + * + * @var Comments + */ + protected $table; + + /** + * Logged in user (or false) + * + * @var User|bool + */ + protected $user; + + /** + * Are comments enabled? + * + * @var bool + */ + protected $enabled; + + /** + * Constructor + * + * @param Comments $table Comments database table + * @param User|bool $user Logged in user (or false) + * @param bool $enabled Are comments enabled? + */ + public function __construct(Comments $table, $user, $enabled = true) + { + $this->table = $table; + $this->user = $user; + $this->enabled = $enabled; + } + + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + */ + public function handleRequest(Params $params) + { + // Make sure comments are enabled: + if (!$this->enabled) { + return $this->formatResponse( + $this->translate('Comments disabled'), + self::STATUS_ERROR, + 403 + ); + } + + if ($this->user === false) { + return $this->formatResponse( + $this->translate('You must be logged in first'), + self::STATUS_NEED_AUTH, + 401 + ); + } + + $id = $params->fromQuery('id'); + if (empty($id)) { + return $this->formatResponse( + $this->translate('bulk_error_missing'), + self::STATUS_ERROR, + 400 + ); + } + if (!$this->table->deleteIfOwnedByUser($id, $this->user)) { + return $this->formatResponse( + $this->translate('edit_list_fail'), + self::STATUS_ERROR, + 403 + ); + } + + return $this->formatResponse($this->translate('Done')); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/DeleteRecordCommentFactory.php b/module/VuFind/src/VuFind/AjaxHandler/DeleteRecordCommentFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..33432dcc72e33d5c58aa3ebcd39497e9a4059d6b --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/DeleteRecordCommentFactory.php @@ -0,0 +1,74 @@ +<?php +/** + * Factory for DeleteRecordComment AJAX handler. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Interop\Container\ContainerInterface; + +/** + * Factory for DeleteRecordComment AJAX handler. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class DeleteRecordCommentFactory + implements \Zend\ServiceManager\Factory\FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options passed to factory.'); + } + $tablePluginManager = $container->get('VuFind\Db\Table\PluginManager'); + $capabilities = $container->get('VuFind\Config\AccountCapabilities'); + return new $requestedName( + $tablePluginManager->get('VuFind\Db\Table\Comments'), + $container->get('VuFind\Auth\Manager')->isLoggedIn(), + $capabilities->getCommentSetting() !== 'disabled' + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetACSuggestions.php b/module/VuFind/src/VuFind/AjaxHandler/GetACSuggestions.php new file mode 100644 index 0000000000000000000000000000000000000000..e2b82a834e4b2f5385687889864ba9319d2d6103 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetACSuggestions.php @@ -0,0 +1,78 @@ +<?php +/** + * "Get Autocomplete Suggestions" AJAX handler + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use VuFind\Autocomplete\Suggester; +use VuFind\Session\Settings as SessionSettings; +use Zend\Mvc\Controller\Plugin\Params; +use Zend\Stdlib\Parameters; + +/** + * "Get Autocomplete Suggestions" AJAX handler + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetACSuggestions extends AbstractBase +{ + /** + * Autocomplete suggester + * + * @var Suggester + */ + protected $suggester; + + /** + * Constructor + * + * @param SessionSettings $ss Session settings + * @param Suggester $suggester Autocomplete suggester + */ + public function __construct(SessionSettings $ss, Suggester $suggester) + { + $this->sessionSettings = $ss; + $this->suggester = $suggester; + } + + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + */ + public function handleRequest(Params $params) + { + $this->disableSessionWrites(); // avoid session write timing bug + $query = new Parameters($params->fromQuery()); + return $this->formatResponse($this->suggester->getSuggestions($query)); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetACSuggestionsFactory.php b/module/VuFind/src/VuFind/AjaxHandler/GetACSuggestionsFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..5a5889631ae7a55b00e20f3d8e1b2c37042a86ec --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetACSuggestionsFactory.php @@ -0,0 +1,71 @@ +<?php +/** + * Factory for GetACSuggestions AJAX handler. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Interop\Container\ContainerInterface; + +/** + * Factory for GetACSuggestions AJAX handler. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetACSuggestionsFactory implements + \Zend\ServiceManager\Factory\FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options passed to factory.'); + } + return new $requestedName( + $container->get('VuFind\Session\Settings'), + $container->get('VuFind\Autocomplete\Suggester') + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetFacetData.php b/module/VuFind/src/VuFind/AjaxHandler/GetFacetData.php new file mode 100644 index 0000000000000000000000000000000000000000..b5080c6c610f3e836cc294442a593a8ad5e2d24f --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetFacetData.php @@ -0,0 +1,121 @@ +<?php +/** + * "Get Facet Data" AJAX handler + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use VuFind\Search\Solr\HierarchicalFacetHelper; +use VuFind\Search\Solr\Results; +use VuFind\Session\Settings as SessionSettings; +use Zend\Mvc\Controller\Plugin\Params; +use Zend\Stdlib\Parameters; + +/** + * "Get Facet Data" AJAX handler + * + * Get hierarchical facet data for jsTree + * + * Parameters: + * facetName The facet to retrieve + * facetSort By default all facets are sorted by count. Two values are available + * for alternative sorting: + * top = sort the top level alphabetically, rest by count + * all = sort all levels alphabetically + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetFacetData extends AbstractBase +{ + /** + * Hierarchical facet helper + * + * @var HierarchicalFacetHelper + */ + protected $facetHelper; + + /** + * Solr search results object + * + * @var Results + */ + protected $results; + + /** + * Constructor + * + * @param SessionSettings $ss Session settings + * @param HierarchicalFacetHelper $fh Facet helper + * @param Results $results Solr results object + */ + public function __construct(SessionSettings $ss, HierarchicalFacetHelper $fh, + Results $results + ) { + $this->sessionSettings = $ss; + $this->facetHelper = $fh; + $this->results = $results; + } + + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + */ + public function handleRequest(Params $params) + { + $this->disableSessionWrites(); // avoid session write timing bug + + $facet = $params->fromQuery('facetName'); + $sort = $params->fromQuery('facetSort'); + $operator = $params->fromQuery('facetOperator'); + + $paramsObj = $this->results->getParams(); + $paramsObj->addFacet($facet, null, $operator === 'OR'); + $paramsObj->initFromRequest(new Parameters($params->fromQuery())); + + $facets = $this->results->getFullFieldFacets([$facet], false, -1, 'count'); + if (empty($facets[$facet]['data']['list'])) { + return $this->formatResponse([]); + } + + $facetList = $facets[$facet]['data']['list']; + + if (!empty($sort)) { + $this->facetHelper->sortFacetList($facetList, $sort == 'top'); + } + + return $this->formatResponse( + $this->facetHelper->buildFacetArray( + $facet, $facetList, $this->results->getUrlQuery() + ) + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetFacetDataFactory.php b/module/VuFind/src/VuFind/AjaxHandler/GetFacetDataFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..d8096535fc7c870e01c09ab250c55ca2486749eb --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetFacetDataFactory.php @@ -0,0 +1,71 @@ +<?php +/** + * Factory for GetFacetData AJAX handler. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Interop\Container\ContainerInterface; + +/** + * Factory for GetFacetData AJAX handler. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetFacetDataFactory implements \Zend\ServiceManager\Factory\FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options passed to factory.'); + } + return new $requestedName( + $container->get('VuFind\Session\Settings'), + $container->get('VuFind\Search\Solr\HierarchicalFacetHelper'), + $container->get('VuFind\Search\Results\PluginManager')->get('Solr') + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetIlsStatus.php b/module/VuFind/src/VuFind/AjaxHandler/GetIlsStatus.php new file mode 100644 index 0000000000000000000000000000000000000000..b9d3c8c1b4e561f0979ad63bc7d37c9d7e16eb3a --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetIlsStatus.php @@ -0,0 +1,99 @@ +<?php +/** + * "Get ILS Status" AJAX handler + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @author André Lahmann <lahmann@ub.uni-leipzig.de> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use VuFind\ILS\Connection; +use VuFind\Session\Settings as SessionSettings; +use Zend\Mvc\Controller\Plugin\Params; +use Zend\View\Renderer\RendererInterface; + +/** + * "Get ILS Status" AJAX handler + * + * This will check the ILS for being online and will return the ils-offline + * template upon failure. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @author André Lahmann <lahmann@ub.uni-leipzig.de> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetIlsStatus extends AbstractBase +{ + /** + * ILS connection + * + * @var Connection + */ + protected $ils; + + /** + * View renderer + * + * @var RendererInterface + */ + protected $renderer; + + /** + * Constructor + * + * @param SessionSettings $ss Session settings + * @param Connection $ils ILS connection + * @param RendererInterface $renderer View renderer + */ + public function __construct(SessionSettings $ss, Connection $ils, + RendererInterface $renderer + ) { + $this->sessionSettings = $ss; + $this->ils = $ils; + $this->renderer = $renderer; + } + + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + */ + public function handleRequest(Params $params) + { + $this->disableSessionWrites(); + if ($this->ils->getOfflineMode(true) == 'ils-offline') { + $offlineModeMsg = $params->fromPost( + 'offlineModeMsg', $params->fromQuery('offlineModeMsg') + ); + $html = $this->renderer + ->render('Helpers/ils-offline.phtml', compact('offlineModeMsg')); + } + return $this->formatResponse($html ?? ''); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetIlsStatusFactory.php b/module/VuFind/src/VuFind/AjaxHandler/GetIlsStatusFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..3481046ce7d0a5b686982078be7745a0f1194497 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetIlsStatusFactory.php @@ -0,0 +1,71 @@ +<?php +/** + * Factory for GetIlsStatus AJAX handler. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Interop\Container\ContainerInterface; + +/** + * Factory for GetIlsStatus AJAX handler. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetIlsStatusFactory implements \Zend\ServiceManager\Factory\FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options passed to factory.'); + } + return new $requestedName( + $container->get('VuFind\Session\Settings'), + $container->get('VuFind\ILS\Connection'), + $container->get('ViewRenderer') + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetItemStatuses.php b/module/VuFind/src/VuFind/AjaxHandler/GetItemStatuses.php new file mode 100644 index 0000000000000000000000000000000000000000..4c74903066e7fe0e029e56f23284d7ea642db233 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetItemStatuses.php @@ -0,0 +1,491 @@ +<?php +/** + * "Get Item Status" AJAX handler + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @author Chris Delis <cedelis@uillinois.edu> + * @author Tuan Nguyen <tuan@yorku.ca> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use VuFind\I18n\Translator\TranslatorAwareInterface; +use VuFind\ILS\Connection; +use VuFind\ILS\Logic\Holds; +use VuFind\Session\Settings as SessionSettings; +use Zend\Config\Config; +use Zend\Mvc\Controller\Plugin\Params; +use Zend\View\Renderer\RendererInterface; + +/** + * "Get Item Status" AJAX handler + * + * This is responsible for printing the holdings information for a + * collection of records in JSON format. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @author Chris Delis <cedelis@uillinois.edu> + * @author Tuan Nguyen <tuan@yorku.ca> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetItemStatuses extends AbstractBase implements TranslatorAwareInterface +{ + use \VuFind\I18n\Translator\TranslatorAwareTrait; + + /** + * Top-level configuration + * + * @var Config + */ + protected $config; + + /** + * ILS connection + * + * @var Connection + */ + protected $ils; + + /** + * View renderer + * + * @var RendererInterface + */ + protected $renderer; + + /** + * Holds logic + * + * @var Holds + */ + protected $holdLogic; + + /** + * Constructor + * + * @param SessionSettings $ss Session settings + * @param Config $config Top-level configuration + * @param Connection $ils ILS connection + * @param RendererInterface $renderer View renderer + * @param Holds $holdLogic Holds logic + */ + public function __construct(SessionSettings $ss, Config $config, Connection $ils, + RendererInterface $renderer, Holds $holdLogic + ) { + $this->sessionSettings = $ss; + $this->config = $config; + $this->ils = $ils; + $this->renderer = $renderer; + $this->holdLogic = $holdLogic; + } + + /** + * Support method for getItemStatuses() -- filter suppressed locations from the + * array of item information for a particular bib record. + * + * @param array $record Information on items linked to a single bib record + * + * @return array Filtered version of $record + */ + protected function filterSuppressedLocations($record) + { + static $hideHoldings = false; + if ($hideHoldings === false) { + $hideHoldings = $this->holdLogic->getSuppressedLocations(); + } + + $filtered = []; + foreach ($record as $current) { + if (!in_array($current['location'], $hideHoldings)) { + $filtered[] = $current; + } + } + return $filtered; + } + + /** + * Translate an array of strings using a prefix. + * + * @param string $transPrefix Translation prefix + * @param array $list List of values to translate + * + * @return array + */ + protected function translateList($transPrefix, $list) + { + $transList = []; + foreach ($list as $current) { + $transList[] = $this->translate( + $transPrefix . $current, [], $current + ); + } + return $transList; + } + + /** + * Support method for getItemStatuses() -- when presented with multiple values, + * pick which one(s) to send back via AJAX. + * + * @param array $rawList Array of values to choose from. + * @param string $mode config.ini setting -- first, all or msg + * @param string $msg Message to display if $mode == "msg" + * @param string $transPrefix Translator prefix to apply to values (false to + * omit translation of values) + * + * @return string + */ + protected function pickValue($rawList, $mode, $msg, $transPrefix = false) + { + // Make sure array contains only unique values: + $list = array_unique($rawList); + + // If there is only one value in the list, or if we're in "first" mode, + // send back the first list value: + if ($mode == 'first' || count($list) == 1) { + return $transPrefix + ? $this->translate($transPrefix . $list[0], [], $list[0]) + : $list[0]; + } elseif (count($list) == 0) { + // Empty list? Return a blank string: + return ''; + } elseif ($mode == 'all') { + // All values mode? Return comma-separated values: + return implode( + ",\t", + $transPrefix ? $this->translateList($transPrefix, $list) : $list + ); + } else { + // Message mode? Return the specified message, translated to the + // appropriate language. + return $this->translate($msg); + } + } + + /** + * Based on settings and the number of callnumbers, return callnumber handler + * Use callnumbers before pickValue is run. + * + * @param array $list Array of callnumbers. + * @param string $displaySetting config.ini setting -- first, all or msg + * + * @return string + */ + protected function getCallnumberHandler($list = null, $displaySetting = null) + { + if ($displaySetting == 'msg' && count($list) > 1) { + return false; + } + return isset($this->config->Item_Status->callnumber_handler) + ? $this->config->Item_Status->callnumber_handler + : false; + } + + /** + * Reduce an array of service names to a human-readable string. + * + * @param array $rawServices Names of available services. + * + * @return string + */ + protected function reduceServices(array $rawServices) + { + // Normalize, dedup and sort available services + $normalize = function ($in) { + return strtolower(preg_replace('/[^A-Za-z]/', '', $in)); + }; + $services = array_map($normalize, array_unique($rawServices)); + sort($services); + + // Do we need to deal with a preferred service? + $preferred = isset($this->config->Item_Status->preferred_service) + ? $normalize($this->config->Item_Status->preferred_service) : false; + if (false !== $preferred && in_array($preferred, $services)) { + $services = [$preferred]; + } + + return $this->renderer->render( + 'ajax/status-available-services.phtml', + ['services' => $services] + ); + } + + /** + * Support method for getItemStatuses() -- process a single bibliographic record + * for location settings other than "group". + * + * @param array $record Information on items linked to a single bib + * record + * @param array $messages Custom status HTML + * (keys = available/unavailable) + * @param string $locationSetting The location mode setting used for + * pickValue() + * @param string $callnumberSetting The callnumber mode setting used for + * pickValue() + * + * @return array Summarized availability information + */ + protected function getItemStatus($record, $messages, $locationSetting, + $callnumberSetting + ) { + // Summarize call number, location and availability info across all items: + $callNumbers = $locations = []; + $use_unknown_status = $available = false; + $services = []; + + foreach ($record as $info) { + // Find an available copy + if ($info['availability']) { + $available = true; + } + // Check for a use_unknown_message flag + if (isset($info['use_unknown_message']) + && $info['use_unknown_message'] == true + ) { + $use_unknown_status = true; + } + // Store call number/location info: + $callNumbers[] = $info['callnumber']; + $locations[] = $info['location']; + // Store all available services + if (isset($info['services'])) { + $services = array_merge($services, $info['services']); + } + } + + $callnumberHandler = $this->getCallnumberHandler( + $callNumbers, $callnumberSetting + ); + + // Determine call number string based on findings: + $callNumber = $this->pickValue( + $callNumbers, $callnumberSetting, 'Multiple Call Numbers' + ); + + // Determine location string based on findings: + $location = $this->pickValue( + $locations, $locationSetting, 'Multiple Locations', 'location_' + ); + + if (!empty($services)) { + $availability_message = $this->reduceServices($services); + } else { + $availability_message = $use_unknown_status + ? $messages['unknown'] + : $messages[$available ? 'available' : 'unavailable']; + } + + // Send back the collected details: + return [ + 'id' => $record[0]['id'], + 'availability' => ($available ? 'true' : 'false'), + 'availability_message' => $availability_message, + 'location' => htmlentities($location, ENT_COMPAT, 'UTF-8'), + 'locationList' => false, + 'reserve' => + ($record[0]['reserve'] == 'Y' ? 'true' : 'false'), + 'reserve_message' => $record[0]['reserve'] == 'Y' + ? $this->translate('on_reserve') + : $this->translate('Not On Reserve'), + 'callnumber' => htmlentities($callNumber, ENT_COMPAT, 'UTF-8'), + 'callnumber_handler' => $callnumberHandler + ]; + } + + /** + * Support method for getItemStatuses() -- process a single bibliographic record + * for "group" location setting. + * + * @param array $record Information on items linked to a single + * bib record + * @param array $messages Custom status HTML + * (keys = available/unavailable) + * @param string $callnumberSetting The callnumber mode setting used for + * pickValue() + * + * @return array Summarized availability information + */ + protected function getItemStatusGroup($record, $messages, $callnumberSetting) + { + // Summarize call number, location and availability info across all items: + $locations = []; + $use_unknown_status = $available = false; + foreach ($record as $info) { + // Find an available copy + if ($info['availability']) { + $available = $locations[$info['location']]['available'] = true; + } + // Check for a use_unknown_message flag + if (isset($info['use_unknown_message']) + && $info['use_unknown_message'] == true + ) { + $use_unknown_status = true; + $locations[$info['location']]['status_unknown'] = true; + } + // Store call number/location info: + $locations[$info['location']]['callnumbers'][] = $info['callnumber']; + } + + // Build list split out by location: + $locationList = false; + foreach ($locations as $location => $details) { + $locationCallnumbers = array_unique($details['callnumbers']); + // Determine call number string based on findings: + $callnumberHandler = $this->getCallnumberHandler( + $locationCallnumbers, $callnumberSetting + ); + $locationCallnumbers = $this->pickValue( + $locationCallnumbers, $callnumberSetting, 'Multiple Call Numbers' + ); + $locationInfo = [ + 'availability' => + $details['available'] ?? false, + 'location' => htmlentities( + $this->translate('location_' . $location, [], $location), + ENT_COMPAT, 'UTF-8' + ), + 'callnumbers' => + htmlentities($locationCallnumbers, ENT_COMPAT, 'UTF-8'), + 'status_unknown' => $details['status_unknown'] ?? false, + 'callnumber_handler' => $callnumberHandler + ]; + $locationList[] = $locationInfo; + } + + $availability_message = $use_unknown_status + ? $messages['unknown'] + : $messages[$available ? 'available' : 'unavailable']; + + // Send back the collected details: + return [ + 'id' => $record[0]['id'], + 'availability' => ($available ? 'true' : 'false'), + 'availability_message' => $availability_message, + 'location' => false, + 'locationList' => $locationList, + 'reserve' => + ($record[0]['reserve'] == 'Y' ? 'true' : 'false'), + 'reserve_message' => $record[0]['reserve'] == 'Y' + ? $this->translate('on_reserve') + : $this->translate('Not On Reserve'), + 'callnumber' => false + ]; + } + + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + */ + public function handleRequest(Params $params) + { + $this->disableSessionWrites(); // avoid session write timing bug + $ids = $params->fromPost('id', $params->fromQuery('id', [])); + $results = $this->ils->getStatuses($ids); + + if (!is_array($results)) { + // If getStatuses returned garbage, let's turn it into an empty array + // to avoid triggering a notice in the foreach loop below. + $results = []; + } + + // In order to detect IDs missing from the status response, create an + // array with a key for every requested ID. We will clear keys as we + // encounter IDs in the response -- anything left will be problems that + // need special handling. + $missingIds = array_flip($ids); + + // Load messages for response: + $messages = [ + 'available' => $this->renderer->render('ajax/status-available.phtml'), + 'unavailable' => + $this->renderer->render('ajax/status-unavailable.phtml'), + 'unknown' => $this->renderer->render('ajax/status-unknown.phtml') + ]; + + // Load callnumber and location settings: + $callnumberSetting = isset($this->config->Item_Status->multiple_call_nos) + ? $this->config->Item_Status->multiple_call_nos : 'msg'; + $locationSetting = isset($this->config->Item_Status->multiple_locations) + ? $this->config->Item_Status->multiple_locations : 'msg'; + $showFullStatus = isset($this->config->Item_Status->show_full_status) + ? $this->config->Item_Status->show_full_status : false; + + // Loop through all the status information that came back + $statuses = []; + foreach ($results as $recordNumber => $record) { + // Filter out suppressed locations: + $record = $this->filterSuppressedLocations($record); + + // Skip empty records: + if (count($record)) { + if ($locationSetting == "group") { + $current = $this->getItemStatusGroup( + $record, $messages, $callnumberSetting + ); + } else { + $current = $this->getItemStatus( + $record, $messages, $locationSetting, $callnumberSetting + ); + } + // If a full status display has been requested, append the HTML: + if ($showFullStatus) { + $current['full_status'] = $this->renderer->render( + 'ajax/status-full.phtml', [ + 'statusItems' => $record, + 'callnumberHandler' => $this->getCallnumberHandler() + ] + ); + } + $current['record_number'] = array_search($current['id'], $ids); + $statuses[] = $current; + + // The current ID is not missing -- remove it from the missing list. + unset($missingIds[$current['id']]); + } + } + + // If any IDs were missing, send back appropriate dummy data + foreach ($missingIds as $missingId => $recordNumber) { + $statuses[] = [ + 'id' => $missingId, + 'availability' => 'false', + 'availability_message' => $messages['unavailable'], + 'location' => $this->translate('Unknown'), + 'locationList' => false, + 'reserve' => 'false', + 'reserve_message' => $this->translate('Not On Reserve'), + 'callnumber' => '', + 'missing_data' => true, + 'record_number' => $recordNumber + ]; + } + + // Done + return $this->formatResponse($statuses); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetItemStatusesFactory.php b/module/VuFind/src/VuFind/AjaxHandler/GetItemStatusesFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..c0608b72dd34cb1eb2888ae8eefbf3d5b1b735d3 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetItemStatusesFactory.php @@ -0,0 +1,73 @@ +<?php +/** + * Factory for GetItemStatus AJAX handler. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Interop\Container\ContainerInterface; + +/** + * Factory for GetItemStatus AJAX handler. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetItemStatusesFactory implements \Zend\ServiceManager\Factory\FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options passed to factory.'); + } + return new $requestedName( + $container->get('VuFind\Session\Settings'), + $container->get('VuFind\Config\PluginManager')->get('config'), + $container->get('VuFind\ILS\Connection'), + $container->get('ViewRenderer'), + $container->get('VuFind\ILS\Logic\Holds') + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetLibraryPickupLocations.php b/module/VuFind/src/VuFind/AjaxHandler/GetLibraryPickupLocations.php new file mode 100644 index 0000000000000000000000000000000000000000..eb71b1f5f63773499814f7077e883280c39e2bd9 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetLibraryPickupLocations.php @@ -0,0 +1,97 @@ +<?php +/** + * "Get Library Pickup Locations" AJAX handler + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Zend\Mvc\Controller\Plugin\Params; + +/** + * "Get Library Pickup Locations" AJAX handler + * + * Get pick up locations for a library + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetLibraryPickupLocations extends AbstractIlsAndUserAction +{ + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + */ + public function handleRequest(Params $params) + { + $this->disableSessionWrites(); // avoid session write timing bug + $id = $params->fromQuery('id'); + $pickupLib = $params->fromQuery('pickupLib'); + if (null === $id || null === $pickupLib) { + return $this->formatResponse( + $this->translate('bulk_error_missing'), + self::STATUS_ERROR, + 400 + ); + } + // check if user is logged in + if (!$this->user) { + return $this->formatResponse( + $this->translate('You must be logged in first'), + self::STATUS_NEED_AUTH, + 401 + ); + } + + try { + $patron = $this->ilsAuthenticator->storedCatalogLogin(); + if ($patron) { + $results = $this->ils + ->getILLPickupLocations($id, $pickupLib, $patron); + foreach ($results as &$result) { + if (isset($result['name'])) { + $result['name'] = $this->translate( + 'location_' . $result['name'], + [], + $result['name'] + ); + } + } + return $this->formatResponse(['locations' => $results]); + } + } catch (\Exception $e) { + // Do nothing -- just fail through to the error message below. + } + + return $this->formatResponse( + $this->translate('An error has occurred'), self::STATUS_ERROR, 500 + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetRecordCommentsAsHTML.php b/module/VuFind/src/VuFind/AjaxHandler/GetRecordCommentsAsHTML.php new file mode 100644 index 0000000000000000000000000000000000000000..0241796f7983f4c6f252391fe2a9f1ba233b686e --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetRecordCommentsAsHTML.php @@ -0,0 +1,88 @@ +<?php +/** + * AJAX handler to get list of comments for a record as HTML. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use VuFind\Record\Loader; +use Zend\Mvc\Controller\Plugin\Params; +use Zend\View\Renderer\RendererInterface; + +/** + * AJAX handler to get list of comments for a record as HTML. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetRecordCommentsAsHTML extends AbstractBase +{ + /** + * Record loader + * + * @var Loader + */ + protected $loader; + + /** + * View renderer + * + * @var RendererInterface + */ + protected $renderer; + + /** + * Constructor + * + * @param Connection $loader Record loader + * @param RendererInterface $renderer View renderer + */ + public function __construct(Loader $loader, RendererInterface $renderer) + { + $this->loader = $loader; + $this->renderer = $renderer; + } + + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + */ + public function handleRequest(Params $params) + { + $driver = $this->loader->load( + $params->fromQuery('id'), + $params->fromQuery('source', DEFAULT_SEARCH_BACKEND) + ); + return $this->formatResponse( + $this->renderer->render('record/comments-list.phtml', compact('driver')) + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetRecordCommentsAsHTMLFactory.php b/module/VuFind/src/VuFind/AjaxHandler/GetRecordCommentsAsHTMLFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..22ac0945b305038ed6abe57fccc3573638c1e56f --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetRecordCommentsAsHTMLFactory.php @@ -0,0 +1,71 @@ +<?php +/** + * Factory for GetRecordCommentsAsHTML AJAX handler. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Interop\Container\ContainerInterface; + +/** + * Factory for GetRecordCommentsAsHTML AJAX handler. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetRecordCommentsAsHTMLFactory + implements \Zend\ServiceManager\Factory\FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options passed to factory.'); + } + return new $requestedName( + $container->get('VuFind\Record\Loader'), + $container->get('ViewRenderer') + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetRecordDetails.php b/module/VuFind/src/VuFind/AjaxHandler/GetRecordDetails.php new file mode 100644 index 0000000000000000000000000000000000000000..6c2d975bee05d40fb8254c861c0310e458087a85 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetRecordDetails.php @@ -0,0 +1,138 @@ +<?php +/** + * "Get Record Details" AJAX handler + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use VuFind\Record\Loader; +use VuFind\RecordTab\PluginManager; +use Zend\Http\PhpEnvironment\Request; +use Zend\Mvc\Controller\Plugin\Params; +use Zend\View\Renderer\RendererInterface; + +/** + * "Get Record Details" AJAX handler + * + * Get record for integrated list view. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetRecordDetails extends AbstractBase +{ + /** + * ZF configuration + * + * @var array + */ + protected $config; + + /** + * Request + * + * @var Request + */ + protected $request; + + /** + * Record loader + * + * @var Loader + */ + protected $recordLoader; + + /** + * Record tab plugin manager + * + * @var PluginManager + */ + protected $pluginManager; + + /** + * View renderer + * + * @var RendererInterface + */ + protected $renderer; + + /** + * Constructor + * + * @param array $config ZF configuration + * @param Request $request HTTP request + * @param Loader $loader Record loader + * @param PluginManager $pm RecordTab plugin manager + * @param RendererInterface $renderer Renderer + */ + public function __construct(array $config, Request $request, Loader $loader, + PluginManager $pm, RendererInterface $renderer + ) { + $this->config = $config; + $this->request = $request; + $this->recordLoader = $loader; + $this->pluginManager = $pm; + $this->renderer = $renderer; + } + + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + */ + public function handleRequest(Params $params) + { + $driver = $this->recordLoader + ->load($params->fromQuery('id'), $params->fromQuery('source')); + $viewtype = preg_replace( + '/\W/', '', trim(strtolower($params->fromQuery('type'))) + ); + + $details = $this->pluginManager->getTabDetailsForRecord( + $driver, + $this->config['vufind']['recorddriver_tabs'], + $this->request, + 'Information' + ); + + $html = $this->renderer->render( + "record/ajaxview-" . $viewtype . ".phtml", + [ + 'defaultTab' => $details['default'], + 'driver' => $driver, + 'tabs' => $details['tabs'], + 'backgroundTabs' => $this->pluginManager->getBackgroundTabNames( + $driver, $this->config['vufind']['recorddriver_tabs'] + ) + ] + ); + return $this->formatResponse($html); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetRecordDetailsFactory.php b/module/VuFind/src/VuFind/AjaxHandler/GetRecordDetailsFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..7eda291fa3feb589ee1ea1f4d0d0dc6811184ae5 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetRecordDetailsFactory.php @@ -0,0 +1,74 @@ +<?php +/** + * Factory for GetRecordDetails AJAX handler. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Interop\Container\ContainerInterface; + +/** + * Factory for GetRecordDetails AJAX handler. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetRecordDetailsFactory + implements \Zend\ServiceManager\Factory\FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options passed to factory.'); + } + return new $requestedName( + $container->get('Config'), + $container->get('Request'), + $container->get('VuFind\Record\Loader'), + $container->get('VuFind\RecordTab\PluginManager'), + $container->get('ViewRenderer') + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetRecordTags.php b/module/VuFind/src/VuFind/AjaxHandler/GetRecordTags.php new file mode 100644 index 0000000000000000000000000000000000000000..db774f93dfcc29fbf0669b2dd35e839582d239ac --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetRecordTags.php @@ -0,0 +1,113 @@ +<?php +/** + * AJAX handler to get all tags for a record as HTML. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use VuFind\Db\Row\User; +use VuFind\Db\Table\Tags; +use Zend\Mvc\Controller\Plugin\Params; +use Zend\View\Renderer\RendererInterface; + +/** + * AJAX handler to get all tags for a record as HTML. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetRecordTags extends AbstractBase +{ + /** + * Tags database table + * + * @var Tags + */ + protected $table; + + /** + * Logged in user (or false) + * + * @var User|bool + */ + protected $user; + + /** + * View renderer + * + * @var RendererInterface + */ + protected $renderer; + + /** + * Constructor + * + * @param Tags $table Tags table + * @param User|bool $user Logged in user (or false) + * @param RendererInterface $renderer View renderer + */ + public function __construct(Tags $table, $user, RendererInterface $renderer) + { + $this->table = $table; + $this->user = $user; + $this->renderer = $renderer; + } + + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + */ + public function handleRequest(Params $params) + { + $is_me_id = !$this->user ? null : $this->user->id; + + // Retrieve from database: + $tags = $this->table->getForResource( + $params->fromQuery('id'), + $params->fromQuery('source', DEFAULT_SEARCH_BACKEND), + 0, null, null, 'count', $is_me_id + ); + + // Build data structure for return: + $tagList = []; + foreach ($tags as $tag) { + $tagList[] = [ + 'tag' => $tag->tag, + 'cnt' => $tag->cnt, + 'is_me' => !empty($tag->is_me) + ]; + } + + $viewParams = ['tagList' => $tagList, 'loggedin' => (bool)$this->user]; + $html = $this->renderer->render('record/taglist', $viewParams); + return $this->formatResponse($html); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetRecordTagsFactory.php b/module/VuFind/src/VuFind/AjaxHandler/GetRecordTagsFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..4e751054acf9aebb2313ac13f80d6da47a465a0a --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetRecordTagsFactory.php @@ -0,0 +1,72 @@ +<?php +/** + * Factory for GetRecordTags AJAX handler. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Interop\Container\ContainerInterface; + +/** + * Factory for GetRecordTags AJAX handler. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetRecordTagsFactory implements \Zend\ServiceManager\Factory\FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options passed to factory.'); + } + $tablePluginManager = $container->get('VuFind\Db\Table\PluginManager'); + return new $requestedName( + $tablePluginManager->get('VuFind\Db\Table\Tags'), + $container->get('VuFind\Auth\Manager')->isLoggedIn(), + $container->get('ViewRenderer') + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetRequestGroupPickupLocations.php b/module/VuFind/src/VuFind/AjaxHandler/GetRequestGroupPickupLocations.php new file mode 100644 index 0000000000000000000000000000000000000000..117baafeb57db92a2da5e095a901e3980e5d960c --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetRequestGroupPickupLocations.php @@ -0,0 +1,99 @@ +<?php +/** + * "Get Request Group Pickup Locations" AJAX handler + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Zend\Mvc\Controller\Plugin\Params; + +/** + * "Get Request Group Pickup Locations" AJAX handler + * + * Get pick up locations for a request group + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetRequestGroupPickupLocations extends AbstractIlsAndUserAction +{ + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + */ + public function handleRequest(Params $params) + { + $this->disableSessionWrites(); // avoid session write timing bug + $id = $params->fromQuery('id'); + $requestGroupId = $params->fromQuery('requestGroupId'); + if (null === $id || null === $requestGroupId) { + return $this->formatResponse( + $this->translate('bulk_error_missing'), + self::STATUS_ERROR, + 400 + ); + } + // check if user is logged in + if (!$this->user) { + return $this->formatResponse( + $this->translate('You must be logged in first'), + self::STATUS_NEED_AUTH, + 401 + ); + } + + try { + if ($patron = $this->ilsAuthenticator->storedCatalogLogin()) { + $details = [ + 'id' => $id, + 'requestGroupId' => $requestGroupId + ]; + $results = $this->ils->getPickupLocations($patron, $details); + foreach ($results as &$result) { + if (isset($result['locationDisplay'])) { + $result['locationDisplay'] = $this->translate( + 'location_' . $result['locationDisplay'], + [], + $result['locationDisplay'] + ); + } + } + return $this->formatResponse(['locations' => $results]); + } + } catch (\Exception $e) { + // Do nothing -- just fail through to the error message below. + } + + return $this->formatResponse( + $this->translate('An error has occurred'), self::STATUS_ERROR, 500 + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetResolverLinks.php b/module/VuFind/src/VuFind/AjaxHandler/GetResolverLinks.php new file mode 100644 index 0000000000000000000000000000000000000000..b172940b7d3fc93116093ea366b2fcada4cde4af --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetResolverLinks.php @@ -0,0 +1,167 @@ +<?php +/** + * "Get Resolver Links" AJAX handler + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @author Graham Seaman <Graham.Seaman@rhul.ac.uk> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use VuFind\I18n\Translator\TranslatorAwareInterface; +use VuFind\Resolver\Connection; +use VuFind\Resolver\Driver\PluginManager; +use VuFind\Session\Settings as SessionSettings; +use Zend\Config\Config; +use Zend\Mvc\Controller\Plugin\Params; +use Zend\View\Renderer\RendererInterface; + +/** + * "Get Resolver Links" AJAX handler + * + * Fetch Links from resolver given an OpenURL and format as HTML + * and output the HTML content in JSON object. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @author Graham Seaman <Graham.Seaman@rhul.ac.uk> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetResolverLinks extends AbstractBase implements TranslatorAwareInterface +{ + use \VuFind\I18n\Translator\TranslatorAwareTrait; + + /** + * Resolver driver plugin manager + * + * @var PluginManager + */ + protected $pluginManager; + + /** + * View renderer + * + * @var RendererInterface + */ + protected $renderer; + + /** + * Top-level VuFind configuration (config.ini) + * + * @var Config + */ + protected $config; + + /** + * Constructor + * + * @param SessionSettings $ss Session settings + * @param PluginManager $pm Resolver driver plugin manager + * @param RendererInterface $renderer View renderer + * @param Config $config Top-level VuFind configuration (config.ini) + */ + public function __construct(SessionSettings $ss, PluginManager $pm, + RendererInterface $renderer, Config $config + ) { + $this->sessionSettings = $ss; + $this->pluginManager = $pm; + $this->renderer = $renderer; + $this->config = $config; + } + + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + */ + public function handleRequest(Params $params) + { + $this->disableSessionWrites(); // avoid session write timing bug + $openUrl = $params->fromQuery('openurl', ''); + $searchClassId = $params->fromQuery('searchClassId', ''); + + $resolverType = isset($this->config->OpenURL->resolver) + ? $this->config->OpenURL->resolver : 'other'; + if (!$this->pluginManager->has($resolverType)) { + return $this->formatResponse( + $this->translate("Could not load driver for $resolverType"), + self::STATUS_ERROR, + 500 + ); + } + $resolver = new Connection($this->pluginManager->get($resolverType)); + if (isset($this->config->OpenURL->resolver_cache)) { + $resolver->enableCache($this->config->OpenURL->resolver_cache); + } + $result = $resolver->fetchLinks($openUrl); + + // Sort the returned links into categories based on service type: + $electronic = $print = $services = []; + foreach ($result as $link) { + switch ($link['service_type'] ?? '') { + case 'getHolding': + $print[] = $link; + break; + case 'getWebService': + $services[] = $link; + break; + case 'getDOI': + // Special case -- modify DOI text for special display: + $link['title'] = $this->translate('Get full text'); + $link['coverage'] = ''; + case 'getFullTxt': + default: + $electronic[] = $link; + break; + } + } + + // Get the OpenURL base: + if (isset($this->config->OpenURL->url)) { + // Trim off any parameters (for legacy compatibility -- default config + // used to include extraneous parameters): + list($base) = explode('?', $this->config->OpenURL->url); + } else { + $base = false; + } + + $moreOptionsLink = $resolver->supportsMoreOptionsLink() + ? $resolver->getResolverUrl($openUrl) : ''; + + // Render the links using the view: + $view = [ + 'openUrlBase' => $base, 'openUrl' => $openUrl, 'print' => $print, + 'electronic' => $electronic, 'services' => $services, + 'searchClassId' => $searchClassId, + 'moreOptionsLink' => $moreOptionsLink + ]; + $html = $this->renderer->render('ajax/resolverLinks.phtml', $view); + + // output HTML encoded in JSON object + return $this->formatResponse($html); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetResolverLinksFactory.php b/module/VuFind/src/VuFind/AjaxHandler/GetResolverLinksFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..4aed4717d5d844967cb4053ee74aa55569cc72a0 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetResolverLinksFactory.php @@ -0,0 +1,73 @@ +<?php +/** + * Factory for GetResolverLinks AJAX handler. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Interop\Container\ContainerInterface; + +/** + * Factory for GetResolverLinks AJAX handler. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetResolverLinksFactory + implements \Zend\ServiceManager\Factory\FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options passed to factory.'); + } + return new $requestedName( + $container->get('VuFind\Session\Settings'), + $container->get('VuFind\Resolver\Driver\PluginManager'), + $container->get('ViewRenderer'), + $container->get('VuFind\Config\PluginManager')->get('config') + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetSaveStatuses.php b/module/VuFind/src/VuFind/AjaxHandler/GetSaveStatuses.php new file mode 100644 index 0000000000000000000000000000000000000000..b223fefc561070ae2a20f84443dfad9acd9e7777 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetSaveStatuses.php @@ -0,0 +1,154 @@ +<?php +/** + * "Get Save Statuses" AJAX handler + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use VuFind\Db\Row\User; +use VuFind\I18n\Translator\TranslatorAwareInterface; +use VuFind\Session\Settings as SessionSettings; +use Zend\Mvc\Controller\Plugin\Params; +use Zend\Mvc\Controller\Plugin\Url; + +/** + * "Get Save Statuses" AJAX handler + * + * Check one or more records to see if they are saved in one of the user's list. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetSaveStatuses extends AbstractBase implements TranslatorAwareInterface +{ + use \VuFind\I18n\Translator\TranslatorAwareTrait; + + /** + * Logged in user (or false) + * + * @var User|bool + */ + protected $user; + + /** + * URL helper + * + * @var Url + */ + protected $urlHelper; + + /** + * Constructor + * + * @param SessionSettings $ss Session settings + * @param User|bool $user Logged in user (or false) + * @param Url $urlHelper URL helper + */ + public function __construct(SessionSettings $ss, $user, Url $urlHelper) + { + $this->sessionSettings = $ss; + $this->user = $user; + $this->urlHelper = $urlHelper; + } + + /** + * Format list object into array. + * + * @param array $list List data + * + * @return array + */ + protected function formatListData($list) + { + return [ + 'list_url' => + $this->urlHelper->fromRoute('userList', ['id' => $list['list_id']]), + 'list_title' => $list['list_title'], + ]; + } + + /** + * Obtain status data from the current logged-in user. + * + * @param array $ids IDs to retrieve + * @param array $sources Source data for IDs (parallel-indexed) + * + * @return array + */ + protected function getDataFromUser($ids, $sources) + { + $result = $checked = []; + foreach ($ids as $i => $id) { + $source = $sources[$i] ?? DEFAULT_SEARCH_BACKEND; + $selector = $source . '|' . $id; + + // We don't want to bother checking the same ID more than once, so + // use the $checked flag array to avoid duplicates: + if (!isset($checked[$selector])) { + $checked[$selector] = true; + + $data = $this->user->getSavedData($id, null, $source); + $result[$selector] = ($data && count($data) > 0) + ? array_map([$this, 'formatListData'], $data->toArray()) : []; + } + } + return $result; + } + + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + */ + public function handleRequest(Params $params) + { + $this->disableSessionWrites(); // avoid session write timing bug + // check if user is logged in + if (!$this->user) { + return $this->formatResponse( + $this->translate('You must be logged in first'), + self::STATUS_NEED_AUTH, + 401 + ); + } + + // loop through each ID check if it is saved to any of the user's lists + $ids = $params->fromPost('id', $params->fromQuery('id', [])); + $sources = $params->fromPost('source', $params->fromQuery('source', [])); + if (!is_array($ids) || !is_array($sources)) { + return $this->formatResponse( + $this->translate('Argument must be array.'), + self::STATUS_ERROR, + 400 + ); + } + return $this->formatResponse($this->getDataFromUser($ids, $sources)); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetSaveStatusesFactory.php b/module/VuFind/src/VuFind/AjaxHandler/GetSaveStatusesFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..9d966a549f28aa44b63cb1a3ae232341e76b0ab6 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetSaveStatusesFactory.php @@ -0,0 +1,71 @@ +<?php +/** + * Factory for GetSaveStatuses AJAX handler. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Interop\Container\ContainerInterface; + +/** + * Factory for GetSaveStatuses AJAX handler. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetSaveStatusesFactory implements \Zend\ServiceManager\Factory\FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options passed to factory.'); + } + return new $requestedName( + $container->get('VuFind\Session\Settings'), + $container->get('VuFind\Auth\Manager')->isLoggedIn(), + $container->get('ControllerPluginManager')->get('url') + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetVisData.php b/module/VuFind/src/VuFind/AjaxHandler/GetVisData.php new file mode 100644 index 0000000000000000000000000000000000000000..8c31a27b1e9e1e7b34eb72fe3fcd20c169561e00 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetVisData.php @@ -0,0 +1,157 @@ +<?php +/** + * "Get Visualization Data" AJAX handler + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @author Chris Hallberg <crhallberg@gmail.com> + * @author Till Kinstler <kinstler@gbv.de> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use VuFind\Search\Solr\Results; +use VuFind\Session\Settings as SessionSettings; +use Zend\Mvc\Controller\Plugin\Params; +use Zend\Stdlib\Parameters; + +/** + * "Get Visualization Data" AJAX handler + * + * AJAX for timeline feature (PubDateVisAjax) + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @author Chris Hallberg <crhallberg@gmail.com> + * @author Till Kinstler <kinstler@gbv.de> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetVisData extends AbstractBase +{ + /** + * Solr search results object + * + * @var Results + */ + protected $results; + + /** + * Constructor + * + * @param SessionSettings $ss Session settings + * @param Results $results Solr search results object + */ + public function __construct(SessionSettings $ss, Results $results) + { + $this->sessionSettings = $ss; + $this->results = $results; + } + + /** + * Extract details from applied filters. + * + * @param array $filters Current filter list + * @param array $dateFacets Objects containing the date ranges + * + * @return array + */ + protected function processDateFacets($filters, $dateFacets) + { + $result = []; + foreach ($dateFacets as $current) { + $from = $to = ''; + if (isset($filters[$current])) { + foreach ($filters[$current] as $filter) { + if (preg_match('/\[[\d\*]+ TO [\d\*]+\]/', $filter)) { + $range = explode(' TO ', trim($filter, '[]')); + $from = $range[0] == '*' ? '' : $range[0]; + $to = $range[1] == '*' ? '' : $range[1]; + break; + } + } + } + $result[$current] = [$from, $to]; + $result[$current]['label'] + = $this->results->getParams()->getFacetLabel($current); + } + return $result; + } + + /** + * Filter bad values from facet lists and add useful data fields. + * + * @param array $filters Current filter list + * @param array $fields Processed date information from processDateFacets + * + * @return array + */ + protected function processFacetValues($filters, $fields) + { + $facets = $this->results->getFullFieldFacets(array_keys($fields)); + $retVal = []; + foreach ($facets as $field => $values) { + $filter = $filters[$field][0] ?? null; + $newValues = [ + 'data' => [], + 'min' => $fields[$field][0] > 0 ? $fields[$field][0] : 0, + 'max' => $fields[$field][1] > 0 ? $fields[$field][1] : 0, + 'removalURL' => $this->results->getUrlQuery() + ->removeFacet($field, $filter)->getParams(false), + ]; + foreach ($values['data']['list'] as $current) { + // Only retain numeric values! + if (preg_match("/^[0-9]+$/", $current['value'])) { + $newValues['data'][] + = [$current['value'], $current['count']]; + } + } + $retVal[$field] = $newValues; + } + return $retVal; + } + + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + */ + public function handleRequest(Params $params) + { + $this->disableSessionWrites(); // avoid session write timing bug + $paramsObj = $this->results->getParams(); + $paramsObj->initFromRequest(new Parameters($params->fromQuery())); + foreach ($params->fromQuery('hf', []) as $hf) { + $paramsObj->addHiddenFilter($hf); + } + $paramsObj->getOptions()->disableHighlighting(); + $paramsObj->getOptions()->spellcheckEnabled(false); + $filters = $paramsObj->getFilters(); + $rawDateFacets = $params->fromQuery('facetFields'); + $dateFacets = empty($rawDateFacets) ? [] : explode(':', $rawDateFacets); + $fields = $this->processDateFacets($filters, $dateFacets); + return $this->formatResponse($this->processFacetValues($filters, $fields)); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/GetVisDataFactory.php b/module/VuFind/src/VuFind/AjaxHandler/GetVisDataFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..e05b92167b2c4734d77afd114739b139ded07dbc --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/GetVisDataFactory.php @@ -0,0 +1,70 @@ +<?php +/** + * Factory for GetVisData AJAX handler. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Interop\Container\ContainerInterface; + +/** + * Factory for GetVisData AJAX handler. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetVisDataFactory implements \Zend\ServiceManager\Factory\FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options passed to factory.'); + } + return new $requestedName( + $container->get('VuFind\Session\Settings'), + $container->get('VuFind\Search\Results\PluginManager')->get('Solr') + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/KeepAlive.php b/module/VuFind/src/VuFind/AjaxHandler/KeepAlive.php new file mode 100644 index 0000000000000000000000000000000000000000..d7fe8f4c85213b81a4f71d4c33eb23ea9f609242 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/KeepAlive.php @@ -0,0 +1,79 @@ +<?php +/** + * "Keep Alive" AJAX handler + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Zend\Mvc\Controller\Plugin\Params; +use Zend\Session\SessionManager; + +/** + * "Keep Alive" AJAX handler + * + * This is responsible for keeping the session alive whenever called + * (via JavaScript) + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class KeepAlive extends AbstractBase +{ + /** + * Session Manager + * + * @var SessionManager + */ + protected $sessionManager; + + /** + * Constructor + * + * @param SessionManager $sm Session manager + */ + public function __construct(SessionManager $sm) + { + $this->sessionManager = $sm; + } + + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function handleRequest(Params $params) + { + // Request ID from session to mark it active + $this->sessionManager->getId(); + return $this->formatResponse(true); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/KeepAliveFactory.php b/module/VuFind/src/VuFind/AjaxHandler/KeepAliveFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..88f7391db5029886ad46e9e4d678576ad2b9731b --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/KeepAliveFactory.php @@ -0,0 +1,67 @@ +<?php +/** + * Factory for KeepAlive AJAX handler. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Interop\Container\ContainerInterface; + +/** + * Factory for KeepAlive AJAX handler. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class KeepAliveFactory implements \Zend\ServiceManager\Factory\FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options passed to factory.'); + } + return new $requestedName($container->get('Zend\Session\SessionManager')); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/PluginManager.php b/module/VuFind/src/VuFind/AjaxHandler/PluginManager.php new file mode 100644 index 0000000000000000000000000000000000000000..b78caad5750af768df8e03c28986dfac7e0152d0 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/PluginManager.php @@ -0,0 +1,122 @@ +<?php +/** + * AJAX handler plugin manager + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +/** + * AJAX handler plugin manager + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager +{ + /** + * Default plugin aliases. + * + * @var array + */ + protected $aliases = [ + 'checkRequestIsValid' => 'VuFind\AjaxHandler\CheckRequestIsValid', + 'commentRecord' => 'VuFind\AjaxHandler\CommentRecord', + 'deleteRecordComment' => 'VuFind\AjaxHandler\DeleteRecordComment', + 'getACSuggestions' => 'VuFind\AjaxHandler\GetACSuggestions', + 'getFacetData' => 'VuFind\AjaxHandler\GetFacetData', + 'getIlsStatus' => 'VuFind\AjaxHandler\GetIlsStatus', + 'getItemStatuses' => 'VuFind\AjaxHandler\GetItemStatuses', + 'getLibraryPickupLocations' => + 'VuFind\AjaxHandler\GetLibraryPickupLocations', + 'getRecordCommentsAsHTML' => 'VuFind\AjaxHandler\GetRecordCommentsAsHTML', + 'getRecordDetails' => 'VuFind\AjaxHandler\GetRecordDetails', + 'getRecordTags' => 'VuFind\AjaxHandler\GetRecordTags', + 'getRequestGroupPickupLocations' => + 'VuFind\AjaxHandler\GetRequestGroupPickupLocations', + 'getResolverLinks' => 'VuFind\AjaxHandler\GetResolverLinks', + 'getSaveStatuses' => 'VuFind\AjaxHandler\GetSaveStatuses', + 'getVisData' => 'VuFind\AjaxHandler\GetVisData', + 'keepAlive' => 'VuFind\AjaxHandler\KeepAlive', + 'recommend' => 'VuFind\AjaxHandler\Recommend', + 'systemStatus' => 'VuFind\AjaxHandler\SystemStatus', + 'tagRecord' => 'VuFind\AjaxHandler\TagRecord', + ]; + + /** + * Default plugin factories. + * + * @var array + */ + protected $factories = [ + 'VuFind\AjaxHandler\CheckRequestIsValid' => + 'VuFind\AjaxHandler\AbstractIlsAndUserActionFactory', + 'VuFind\AjaxHandler\CommentRecord' => + 'VuFind\AjaxHandler\CommentRecordFactory', + 'VuFind\AjaxHandler\DeleteRecordComment' => + 'VuFind\AjaxHandler\DeleteRecordCommentFactory', + 'VuFind\AjaxHandler\GetACSuggestions' => + 'VuFind\AjaxHandler\GetACSuggestionsFactory', + 'VuFind\AjaxHandler\GetFacetData' => + 'VuFind\AjaxHandler\GetFacetDataFactory', + 'VuFind\AjaxHandler\GetIlsStatus' => + 'VuFind\AjaxHandler\GetIlsStatusFactory', + 'VuFind\AjaxHandler\GetItemStatuses' => + 'VuFind\AjaxHandler\GetItemStatusesFactory', + 'VuFind\AjaxHandler\GetLibraryPickupLocations' => + 'VuFind\AjaxHandler\AbstractIlsAndUserActionFactory', + 'VuFind\AjaxHandler\GetRecordCommentsAsHTML' => + 'VuFind\AjaxHandler\GetRecordCommentsAsHTMLFactory', + 'VuFind\AjaxHandler\GetRecordDetails' => + 'VuFind\AjaxHandler\GetRecordDetailsFactory', + 'VuFind\AjaxHandler\GetRecordTags' => + 'VuFind\AjaxHandler\GetRecordTagsFactory', + 'VuFind\AjaxHandler\GetRequestGroupPickupLocations' => + 'VuFind\AjaxHandler\AbstractIlsAndUserActionFactory', + 'VuFind\AjaxHandler\GetResolverLinks' => + 'VuFind\AjaxHandler\GetResolverLinksFactory', + 'VuFind\AjaxHandler\GetSaveStatuses' => + 'VuFind\AjaxHandler\GetSaveStatusesFactory', + 'VuFind\AjaxHandler\GetVisData' => 'VuFind\AjaxHandler\GetVisDataFactory', + 'VuFind\AjaxHandler\KeepAlive' => 'VuFind\AjaxHandler\KeepAliveFactory', + 'VuFind\AjaxHandler\Recommend' => 'VuFind\AjaxHandler\RecommendFactory', + 'VuFind\AjaxHandler\SystemStatus' => + 'VuFind\AjaxHandler\SystemStatusFactory', + 'VuFind\AjaxHandler\TagRecord' => 'VuFind\AjaxHandler\TagRecordFactory', + ]; + + /** + * Return the name of the base class or interface that plug-ins must conform + * to. + * + * @return string + */ + protected function getExpectedInterface() + { + return 'VuFind\AjaxHandler\AjaxHandlerInterface'; + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/Recommend.php b/module/VuFind/src/VuFind/AjaxHandler/Recommend.php new file mode 100644 index 0000000000000000000000000000000000000000..1608ac6fc2c5abe5a6294c856c90a6c4599eeb74 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/Recommend.php @@ -0,0 +1,109 @@ +<?php +/** + * Load a recommendation module via AJAX. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use VuFind\Recommend\PluginManager; +use VuFind\Search\Solr\Results; +use VuFind\Session\Settings as SessionSettings; +use Zend\Mvc\Controller\Plugin\Params; +use Zend\Stdlib\Parameters; +use Zend\View\Renderer\RendererInterface; + +/** + * Load a recommendation module via AJAX. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class Recommend extends AbstractBase +{ + /** + * Recommendation plugin manager + * + * @var PluginManager + */ + protected $pluginManager; + + /** + * Solr search results object + * + * @var Results + */ + protected $results; + + /** + * View renderer + * + * @var RendererInterface + */ + protected $renderer; + + /** + * Constructor + * + * @param SessionSettings $ss Session settings + * @param PluginManager $pm Recommendation plugin manager + * @param Results $results Solr results object + * @param RendererInterface $renderer View renderer + */ + public function __construct(SessionSettings $ss, PluginManager $pm, + Results $results, RendererInterface $renderer + ) { + $this->sessionSettings = $ss; + $this->pluginManager = $pm; + $this->results = $results; + $this->renderer = $renderer; + } + + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + */ + public function handleRequest(Params $params) + { + $this->disableSessionWrites(); // avoid session write timing bug + // Process recommendations -- for now, we assume Solr-based search objects, + // since deferred recommendations work best for modules that don't care about + // the details of the search objects anyway: + $module = $this->pluginManager->get($params->fromQuery('mod')); + $module->setConfig($params->fromQuery('params')); + $paramsObj = $this->results->getParams(); + $module->init($paramsObj, new Parameters($params->fromQuery())); + $module->process($this->results); + + // Render recommendations: + $recommend = $this->renderer->plugin('recommend'); + return $this->formatResponse($recommend($module)); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/RecommendFactory.php b/module/VuFind/src/VuFind/AjaxHandler/RecommendFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..87c525189a6ae7de1ea8183689ff959a46fdeb9a --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/RecommendFactory.php @@ -0,0 +1,72 @@ +<?php +/** + * Factory for Recommend AJAX handler. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Interop\Container\ContainerInterface; + +/** + * Factory for Recommend AJAX handler. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class RecommendFactory implements \Zend\ServiceManager\Factory\FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options passed to factory.'); + } + return new $requestedName( + $container->get('VuFind\Session\Settings'), + $container->get('VuFind\Recommend\PluginManager'), + $container->get('VuFind\Search\Results\PluginManager')->get('Solr'), + $container->get('ViewRenderer') + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/SystemStatus.php b/module/VuFind/src/VuFind/AjaxHandler/SystemStatus.php new file mode 100644 index 0000000000000000000000000000000000000000..46a1cc387e6ca2e58de1fde145709897bbcb94c7 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/SystemStatus.php @@ -0,0 +1,141 @@ +<?php +/** + * "Keep Alive" AJAX handler + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use VuFind\Db\Table\Session; +use VuFind\Search\Results\PluginManager; +use Zend\Config\Config; +use Zend\Mvc\Controller\Plugin\Params; +use Zend\Session\SessionManager; + +/** + * "Keep Alive" AJAX handler + * + * This is responsible for keeping the session alive whenever called + * (via JavaScript) + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class SystemStatus extends AbstractBase +{ + /** + * Session Manager + * + * @var SessionManager + */ + protected $sessionManager; + + /** + * Session database table + * + * @var Session + */ + protected $sessionTable; + + /** + * Results manager + * + * @var PluginManager + */ + protected $resultsManager; + + /** + * Top-level VuFind configuration (config.ini) + * + * @var Config + */ + protected $config; + + /** + * Constructor + * + * @param SessionManager $sm Session manager + * @param PluginManager $rm Results manager + * @param Config $config Top-level VuFind configuration (config.ini) + * @param Session $table Session database table + */ + public function __construct(SessionManager $sm, PluginManager $rm, + Config $config, Session $table + ) { + $this->sessionManager = $sm; + $this->resultsManager = $rm; + $this->config = $config; + $this->sessionTable = $table; + } + + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function handleRequest(Params $params) + { + // Check system status + if (!empty($this->config->System->healthCheckFile) + && file_exists($this->config->System->healthCheckFile) + ) { + return $this->formatResponse( + 'Health check file exists', self::STATUS_ERROR, 503 + ); + } + + // Test search index + try { + $results = $this->resultsManager->get('Solr'); + $paramsObj = $results->getParams(); + $paramsObj->setQueryIDs(['healthcheck']); + $results->performAndProcessSearch(); + } catch (\Exception $e) { + return $this->formatResponse( + 'Search index error: ' . $e->getMessage(), self::STATUS_ERROR, 500 + ); + } + + // Test database connection + try { + $this->sessionTable->getBySessionId('healthcheck', false); + } catch (\Exception $e) { + return $this->formatResponse( + 'Database error: ' . $e->getMessage(), self::STATUS_ERROR, 500 + ); + } + + // This may be called frequently, don't leave sessions dangling + $this->sessionManager->destroy(); + + return $this->formatResponse(''); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/SystemStatusFactory.php b/module/VuFind/src/VuFind/AjaxHandler/SystemStatusFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..0261892d5c2d9fb9d62a4747dae2d838538c5744 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/SystemStatusFactory.php @@ -0,0 +1,73 @@ +<?php +/** + * Factory for SystemStatus AJAX handler. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Interop\Container\ContainerInterface; + +/** + * Factory for SystemStatus AJAX handler. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class SystemStatusFactory implements \Zend\ServiceManager\Factory\FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options passed to factory.'); + } + $tablePluginManager = $container->get('VuFind\Db\Table\PluginManager'); + return new $requestedName( + $container->get('Zend\Session\SessionManager'), + $container->get('VuFind\Search\Results\PluginManager'), + $container->get('VuFind\Config\PluginManager')->get('config'), + $tablePluginManager->get('VuFind\Db\Table\Session') + ); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/TagRecord.php b/module/VuFind/src/VuFind/AjaxHandler/TagRecord.php new file mode 100644 index 0000000000000000000000000000000000000000..6511e6c1472df8e98f58877fd53b4bbf0380e783 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/TagRecord.php @@ -0,0 +1,114 @@ +<?php +/** + * AJAX handler to tag/untag a record. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use VuFind\Db\Row\User; +use VuFind\I18n\Translator\TranslatorAwareInterface; +use VuFind\Record\Loader; +use VuFind\Tags; +use Zend\Mvc\Controller\Plugin\Params; + +/** + * AJAX handler to tag/untag a record. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class TagRecord extends AbstractBase implements TranslatorAwareInterface +{ + use \VuFind\I18n\Translator\TranslatorAwareTrait; + + /** + * Record loader + * + * @var Loader + */ + protected $loader; + + /** + * Tag parser + * + * @var Tags + */ + protected $tagParser; + + /** + * Logged in user (or false) + * + * @var User|bool + */ + protected $user; + + /** + * Constructor + * + * @param Loader $loader Record loader + * @param Tags $parser Tag parser + * @param User|bool $user Logged in user (or false) + */ + public function __construct(Loader $loader, Tags $parser, $user) + { + $this->loader = $loader; + $this->tagParser = $parser; + $this->user = $user; + } + + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + */ + public function handleRequest(Params $params) + { + if (!$this->user) { + return $this->formatResponse( + $this->translate('You must be logged in first'), + self::STATUS_NEED_AUTH, + 401 + ); + } + + $id = $params->fromPost('id'); + $source = $params->fromPost('source', DEFAULT_SEARCH_BACKEND); + $tag = $params->fromPost('tag', ''); + + if (strlen($tag) > 0) { // don't add empty tags + $driver = $this->loader->load($id, $source); + ('false' === $params->fromPost('remove', 'false')) + ? $driver->addTags($this->user, $this->tagParser->parse($tag)) + : $driver->deleteTags($this->user, $this->tagParser->parse($tag)); + } + + return $this->formatResponse($this->translate('Done')); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/TagRecordFactory.php b/module/VuFind/src/VuFind/AjaxHandler/TagRecordFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..3a11f517018034d939771e9e33fb3d63e1709315 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/TagRecordFactory.php @@ -0,0 +1,71 @@ +<?php +/** + * Factory for TagRecord AJAX handler. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Interop\Container\ContainerInterface; + +/** + * Factory for TagRecord AJAX handler. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class TagRecordFactory implements \Zend\ServiceManager\Factory\FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options passed to factory.'); + } + return new $requestedName( + $container->get('VuFind\Record\Loader'), + $container->get('VuFind\Tags'), + $container->get('VuFind\Auth\Manager')->isLoggedIn() + ); + } +} diff --git a/module/VuFind/src/VuFind/Controller/AjaxController.php b/module/VuFind/src/VuFind/Controller/AjaxController.php index 3f8a1367a78cda71cc1efd11fc5d10f363e54027..ea796681bb31fc7a5d5bd5ccaad44a658cbbce33 100644 --- a/module/VuFind/src/VuFind/Controller/AjaxController.php +++ b/module/VuFind/src/VuFind/Controller/AjaxController.php @@ -27,7 +27,9 @@ */ namespace VuFind\Controller; -use Zend\ServiceManager\ServiceLocatorInterface; +use VuFind\AjaxHandler\PluginManager; +use VuFind\I18n\Translator\TranslatorAwareInterface; +use Zend\Mvc\Controller\AbstractActionController; /** * This controller handles global AJAX functionality @@ -38,69 +40,32 @@ use Zend\ServiceManager\ServiceLocatorInterface; * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License * @link https://vufind.org/wiki/development:plugins:controllers Wiki */ -class AjaxController extends AbstractBase +class AjaxController extends AbstractActionController + implements TranslatorAwareInterface { - // define some status constants - const STATUS_OK = 'OK'; // good - const STATUS_ERROR = 'ERROR'; // bad - const STATUS_NEED_AUTH = 'NEED_AUTH'; // must login first - - /** - * Type of output to use - * - * @var string - */ - protected $outputMode; - - /** - * Array of PHP errors captured during execution - * - * @var array - */ - protected static $php_errors = []; + use AjaxResponseTrait; + use \VuFind\I18n\Translator\TranslatorAwareTrait; /** * Constructor * - * @param ServiceLocatorInterface $sm Service locator + * @param PluginManager $am AJAX Handler Plugin Manager */ - public function __construct(ServiceLocatorInterface $sm) + public function __construct(PluginManager $am) { // Add notices to a key in the output - set_error_handler(['VuFind\Controller\AjaxController', "storeError"]); - parent::__construct($sm); + set_error_handler([static::class, 'storeError']); + $this->ajaxManager = $am; } /** - * Handles passing data to the class + * Make an AJAX call with a JSON-formatted response. * - * @return mixed + * @return \Zend\Http\Response */ public function jsonAction() { - // Set the output mode to JSON: - $this->outputMode = 'json'; - - // Call the method specified by the 'method' parameter; append Ajax to - // the end to avoid access to arbitrary inappropriate methods. - $callback = [$this, $this->params()->fromQuery('method') . 'Ajax']; - if (is_callable($callback)) { - try { - return call_user_func($callback); - } catch (\Exception $e) { - $debugMsg = ('development' == APPLICATION_ENV) - ? ': ' . $e->getMessage() : ''; - return $this->output( - $this->translate('An error has occurred') . $debugMsg, - self::STATUS_ERROR, - 500 - ); - } - } else { - return $this->output( - $this->translate('Invalid Method'), self::STATUS_ERROR, 400 - ); - } + return $this->callAjaxMethod($this->params()->fromQuery('method')); } /** @@ -110,1205 +75,7 @@ class AjaxController extends AbstractBase */ public function recommendAction() { - $this->disableSessionWrites(); // avoid session write timing bug - // Process recommendations -- for now, we assume Solr-based search objects, - // since deferred recommendations work best for modules that don't care about - // the details of the search objects anyway: - $rm = $this->serviceLocator->get('VuFind\Recommend\PluginManager'); - $module = $rm->get($this->params()->fromQuery('mod')); - $module->setConfig($this->params()->fromQuery('params')); - $results = $this->getResultsManager()->get('Solr'); - $params = $results->getParams(); - $module->init($params, $this->getRequest()->getQuery()); - $module->process($results); - - // Set headers: - $response = $this->getResponse(); - $headers = $response->getHeaders(); - $headers->addHeaderLine('Content-type', 'text/html'); - $headers->addHeaderLine('Cache-Control', 'no-cache, must-revalidate'); - $headers->addHeaderLine('Expires', 'Mon, 26 Jul 1997 05:00:00 GMT'); - - // Render recommendations: - $recommend = $this->getViewRenderer()->plugin('recommend'); - $response->setContent($recommend($module)); - return $response; - } - - /** - * Support method for getItemStatuses() -- filter suppressed locations from the - * array of item information for a particular bib record. - * - * @param array $record Information on items linked to a single bib record - * - * @return array Filtered version of $record - */ - protected function filterSuppressedLocations($record) - { - static $hideHoldings = false; - if ($hideHoldings === false) { - $logic = $this->serviceLocator->get('VuFind\ILS\Logic\Holds'); - $hideHoldings = $logic->getSuppressedLocations(); - } - - $filtered = []; - foreach ($record as $current) { - if (!in_array($current['location'], $hideHoldings)) { - $filtered[] = $current; - } - } - return $filtered; - } - - /** - * Get Item Statuses - * - * This is responsible for printing the holdings information for a - * collection of records in JSON format. - * - * @return \Zend\Http\Response - * @author Chris Delis <cedelis@uillinois.edu> - * @author Tuan Nguyen <tuan@yorku.ca> - */ - protected function getItemStatusesAjax() - { - $this->disableSessionWrites(); // avoid session write timing bug - $catalog = $this->getILS(); - $ids = $this->params()->fromPost('id', $this->params()->fromQuery('id')); - $results = $catalog->getStatuses($ids); - - if (!is_array($results)) { - // If getStatuses returned garbage, let's turn it into an empty array - // to avoid triggering a notice in the foreach loop below. - $results = []; - } - - // In order to detect IDs missing from the status response, create an - // array with a key for every requested ID. We will clear keys as we - // encounter IDs in the response -- anything left will be problems that - // need special handling. - $missingIds = array_flip($ids); - - // Get access to PHP template renderer for partials: - $renderer = $this->getViewRenderer(); - - // Load messages for response: - $messages = [ - 'available' => $renderer->render('ajax/status-available.phtml'), - 'unavailable' => $renderer->render('ajax/status-unavailable.phtml'), - 'unknown' => $renderer->render('ajax/status-unknown.phtml') - ]; - - // Load callnumber and location settings: - $config = $this->getConfig(); - $callnumberSetting = isset($config->Item_Status->multiple_call_nos) - ? $config->Item_Status->multiple_call_nos : 'msg'; - $locationSetting = isset($config->Item_Status->multiple_locations) - ? $config->Item_Status->multiple_locations : 'msg'; - $showFullStatus = isset($config->Item_Status->show_full_status) - ? $config->Item_Status->show_full_status : false; - - // Loop through all the status information that came back - $statuses = []; - foreach ($results as $recordNumber => $record) { - // Filter out suppressed locations: - $record = $this->filterSuppressedLocations($record); - - // Skip empty records: - if (count($record)) { - if ($locationSetting == "group") { - $current = $this->getItemStatusGroup( - $record, $messages, $callnumberSetting - ); - } else { - $current = $this->getItemStatus( - $record, $messages, $locationSetting, $callnumberSetting - ); - } - // If a full status display has been requested, append the HTML: - if ($showFullStatus) { - $current['full_status'] = $renderer->render( - 'ajax/status-full.phtml', [ - 'statusItems' => $record, - 'callnumberHandler' => $this->getCallnumberHandler() - ] - ); - } - $current['record_number'] = array_search($current['id'], $ids); - $statuses[] = $current; - - // The current ID is not missing -- remove it from the missing list. - unset($missingIds[$current['id']]); - } - } - - // If any IDs were missing, send back appropriate dummy data - foreach ($missingIds as $missingId => $recordNumber) { - $statuses[] = [ - 'id' => $missingId, - 'availability' => 'false', - 'availability_message' => $messages['unavailable'], - 'location' => $this->translate('Unknown'), - 'locationList' => false, - 'reserve' => 'false', - 'reserve_message' => $this->translate('Not On Reserve'), - 'callnumber' => '', - 'missing_data' => true, - 'record_number' => $recordNumber - ]; - } - - // Done - return $this->output($statuses, self::STATUS_OK); - } - - /** - * Support method for getItemStatuses() -- when presented with multiple values, - * pick which one(s) to send back via AJAX. - * - * @param array $list Array of values to choose from. - * @param string $mode config.ini setting -- first, all or msg - * @param string $msg Message to display if $mode == "msg" - * @param string $transPrefix Translator prefix to apply to values (false to - * omit translation of values) - * - * @return string - */ - protected function pickValue($list, $mode, $msg, $transPrefix = false) - { - // Make sure array contains only unique values: - $list = array_unique($list); - - // If there is only one value in the list, or if we're in "first" mode, - // send back the first list value: - if ($mode == 'first' || count($list) == 1) { - if (!$transPrefix) { - return $list[0]; - } else { - return $this->translate($transPrefix . $list[0], [], $list[0]); - } - } elseif (count($list) == 0) { - // Empty list? Return a blank string: - return ''; - } elseif ($mode == 'all') { - // Translate values if necessary: - if ($transPrefix) { - $transList = []; - foreach ($list as $current) { - $transList[] = $this->translate( - $transPrefix . $current, [], $current - ); - } - $list = $transList; - } - // All values mode? Return comma-separated values: - return implode(",\t", $list); - } else { - // Message mode? Return the specified message, translated to the - // appropriate language. - return $this->translate($msg); - } - } - - /** - * Based on settings and the number of callnumbers, return callnumber handler - * Use callnumbers before pickValue is run. - * - * @param array $list Array of callnumbers. - * @param string $displaySetting config.ini setting -- first, all or msg - * - * @return string - */ - protected function getCallnumberHandler($list = null, $displaySetting = null) - { - if ($displaySetting == 'msg' && count($list) > 1) { - return false; - } - $config = $this->getConfig(); - return isset($config->Item_Status->callnumber_handler) - ? $config->Item_Status->callnumber_handler - : false; - } - - /** - * Reduce an array of service names to a human-readable string. - * - * @param array $services Names of available services. - * - * @return string - */ - protected function reduceServices(array $services) - { - // Normalize, dedup and sort available services - $normalize = function ($in) { - return strtolower(preg_replace('/[^A-Za-z]/', '', $in)); - }; - $services = array_map($normalize, array_unique($services)); - sort($services); - - // Do we need to deal with a preferred service? - $config = $this->getConfig(); - $preferred = isset($config->Item_Status->preferred_service) - ? $normalize($config->Item_Status->preferred_service) : false; - if (false !== $preferred && in_array($preferred, $services)) { - $services = [$preferred]; - } - - return $this->getViewRenderer()->render( - 'ajax/status-available-services.phtml', - ['services' => $services] - ); - } - - /** - * Support method for getItemStatuses() -- process a single bibliographic record - * for location settings other than "group". - * - * @param array $record Information on items linked to a single bib - * record - * @param array $messages Custom status HTML - * (keys = available/unavailable) - * @param string $locationSetting The location mode setting used for - * pickValue() - * @param string $callnumberSetting The callnumber mode setting used for - * pickValue() - * - * @return array Summarized availability information - */ - protected function getItemStatus($record, $messages, $locationSetting, - $callnumberSetting - ) { - // Summarize call number, location and availability info across all items: - $callNumbers = $locations = []; - $use_unknown_status = $available = false; - $services = []; - - foreach ($record as $info) { - // Find an available copy - if ($info['availability']) { - $available = true; - } - // Check for a use_unknown_message flag - if (isset($info['use_unknown_message']) - && $info['use_unknown_message'] == true - ) { - $use_unknown_status = true; - } - // Store call number/location info: - $callNumbers[] = $info['callnumber']; - $locations[] = $info['location']; - // Store all available services - if (isset($info['services'])) { - $services = array_merge($services, $info['services']); - } - } - - $callnumberHandler = $this->getCallnumberHandler( - $callNumbers, $callnumberSetting - ); - - // Determine call number string based on findings: - $callNumber = $this->pickValue( - $callNumbers, $callnumberSetting, 'Multiple Call Numbers' - ); - - // Determine location string based on findings: - $location = $this->pickValue( - $locations, $locationSetting, 'Multiple Locations', 'location_' - ); - - if (!empty($services)) { - $availability_message = $this->reduceServices($services); - } else { - $availability_message = $use_unknown_status - ? $messages['unknown'] - : $messages[$available ? 'available' : 'unavailable']; - } - - // Send back the collected details: - return [ - 'id' => $record[0]['id'], - 'availability' => ($available ? 'true' : 'false'), - 'availability_message' => $availability_message, - 'location' => htmlentities($location, ENT_COMPAT, 'UTF-8'), - 'locationList' => false, - 'reserve' => - ($record[0]['reserve'] == 'Y' ? 'true' : 'false'), - 'reserve_message' => $record[0]['reserve'] == 'Y' - ? $this->translate('on_reserve') - : $this->translate('Not On Reserve'), - 'callnumber' => htmlentities($callNumber, ENT_COMPAT, 'UTF-8'), - 'callnumber_handler' => $callnumberHandler - ]; - } - - /** - * Support method for getItemStatuses() -- process a single bibliographic record - * for "group" location setting. - * - * @param array $record Information on items linked to a single - * bib record - * @param array $messages Custom status HTML - * (keys = available/unavailable) - * @param string $callnumberSetting The callnumber mode setting used for - * pickValue() - * - * @return array Summarized availability information - */ - protected function getItemStatusGroup($record, $messages, $callnumberSetting) - { - // Summarize call number, location and availability info across all items: - $locations = []; - $use_unknown_status = $available = false; - foreach ($record as $info) { - // Find an available copy - if ($info['availability']) { - $available = $locations[$info['location']]['available'] = true; - } - // Check for a use_unknown_message flag - if (isset($info['use_unknown_message']) - && $info['use_unknown_message'] == true - ) { - $use_unknown_status = true; - $locations[$info['location']]['status_unknown'] = true; - } - // Store call number/location info: - $locations[$info['location']]['callnumbers'][] = $info['callnumber']; - } - - // Build list split out by location: - $locationList = false; - foreach ($locations as $location => $details) { - $locationCallnumbers = array_unique($details['callnumbers']); - // Determine call number string based on findings: - $callnumberHandler = $this->getCallnumberHandler( - $locationCallnumbers, $callnumberSetting - ); - $locationCallnumbers = $this->pickValue( - $locationCallnumbers, $callnumberSetting, 'Multiple Call Numbers' - ); - $locationInfo = [ - 'availability' => $details['available'] ?? false, - 'location' => htmlentities( - $this->translate('location_' . $location, [], $location), - ENT_COMPAT, 'UTF-8' - ), - 'callnumbers' => - htmlentities($locationCallnumbers, ENT_COMPAT, 'UTF-8'), - 'status_unknown' => $details['status_unknown'] ?? false, - 'callnumber_handler' => $callnumberHandler - ]; - $locationList[] = $locationInfo; - } - - $availability_message = $use_unknown_status - ? $messages['unknown'] - : $messages[$available ? 'available' : 'unavailable']; - - // Send back the collected details: - return [ - 'id' => $record[0]['id'], - 'availability' => ($available ? 'true' : 'false'), - 'availability_message' => $availability_message, - 'location' => false, - 'locationList' => $locationList, - 'reserve' => - ($record[0]['reserve'] == 'Y' ? 'true' : 'false'), - 'reserve_message' => $record[0]['reserve'] == 'Y' - ? $this->translate('on_reserve') - : $this->translate('Not On Reserve'), - 'callnumber' => false - ]; - } - - /** - * Check one or more records to see if they are saved in one of the user's list. - * - * @return \Zend\Http\Response - */ - protected function getSaveStatusesAjax() - { - $this->disableSessionWrites(); // avoid session write timing bug - // check if user is logged in - $user = $this->getUser(); - if (!$user) { - return $this->output( - $this->translate('You must be logged in first'), - self::STATUS_NEED_AUTH, - 401 - ); - } - - // loop through each ID check if it is saved to any of the user's lists - $ids = $this->params()->fromPost('id', $this->params()->fromQuery('id', [])); - $sources = $this->params()->fromPost( - 'source', $this->params()->fromQuery('source', []) - ); - if (!is_array($ids) || !is_array($sources)) { - return $this->output( - $this->translate('Argument must be array.'), - self::STATUS_ERROR, - 400 - ); - } - $result = $checked = []; - foreach ($ids as $i => $id) { - $source = $sources[$i] ?? DEFAULT_SEARCH_BACKEND; - $selector = $source . '|' . $id; - - // We don't want to bother checking the same ID more than once, so - // use the $checked flag array to avoid duplicates: - if (isset($checked[$selector])) { - continue; - } - $checked[$selector] = true; - - $data = $user->getSavedData($id, null, $source); - $result[$selector] = []; - if ($data && count($data) > 0) { - // if this item was saved, add it to the list of saved items. - foreach ($data as $list) { - $result[$selector][] = [ - 'list_url' => $this->url()->fromRoute( - 'userList', - ['id' => $list->list_id] - ), - 'list_title' => $list->list_title - ]; - } - } - } - return $this->output($result, self::STATUS_OK); - } - - /** - * Send output data and exit. - * - * @param mixed $data The response data - * @param string $status Status of the request - * @param int $httpCode A custom HTTP Status Code - * - * @return \Zend\Http\Response - * @throws \Exception - */ - protected function output($data, $status, $httpCode = null) - { - $response = $this->getResponse(); - $headers = $response->getHeaders(); - $headers->addHeaderLine('Cache-Control', 'no-cache, must-revalidate'); - $headers->addHeaderLine('Expires', 'Mon, 26 Jul 1997 05:00:00 GMT'); - if ($httpCode !== null) { - $response->setStatusCode($httpCode); - } - if ($this->outputMode == 'json') { - $headers->addHeaderLine('Content-type', 'application/javascript'); - $output = ['data' => $data, 'status' => $status]; - if ('development' == APPLICATION_ENV && count(self::$php_errors) > 0) { - $output['php_errors'] = self::$php_errors; - } - $response->setContent(json_encode($output)); - return $response; - } elseif ($this->outputMode == 'plaintext') { - $headers->addHeaderLine('Content-type', 'text/plain'); - $response->setContent($data ? $status . " $data" : $status); - return $response; - } else { - throw new \Exception('Unsupported output mode: ' . $this->outputMode); - } - } - - /** - * Store the errors for later, to be added to the output - * - * @param string $errno Error code number - * @param string $errstr Error message - * @param string $errfile File where error occurred - * @param string $errline Line number of error - * - * @return bool Always true to cancel default error handling - */ - public static function storeError($errno, $errstr, $errfile, $errline) - { - self::$php_errors[] = "ERROR [$errno] - " . $errstr . "<br />\n" - . " Occurred in " . $errfile . " on line " . $errline . "."; - return true; - } - - /** - * Tag a record. - * - * @return \Zend\Http\Response - */ - protected function tagRecordAjax() - { - $user = $this->getUser(); - if ($user === false) { - return $this->output( - $this->translate('You must be logged in first'), - self::STATUS_NEED_AUTH, - 401 - ); - } - // empty tag - try { - $driver = $this->getRecordLoader()->load( - $this->params()->fromPost('id'), - $this->params()->fromPost('source', DEFAULT_SEARCH_BACKEND) - ); - $tag = $this->params()->fromPost('tag', ''); - $tagParser = $this->serviceLocator->get('VuFind\Tags'); - if (strlen($tag) > 0) { // don't add empty tags - if ('false' === $this->params()->fromPost('remove', 'false')) { - $driver->addTags($user, $tagParser->parse($tag)); - } else { - $driver->deleteTags($user, $tagParser->parse($tag)); - } - } - } catch (\Exception $e) { - return $this->output( - ('development' == APPLICATION_ENV) ? $e->getMessage() : 'Failed', - self::STATUS_ERROR, - 500 - ); - } - - return $this->output($this->translate('Done'), self::STATUS_OK); - } - - /** - * Get all tags for a record. - * - * @return \Zend\Http\Response - */ - protected function getRecordTagsAjax() - { - $user = $this->getUser(); - $is_me_id = null === $user ? null : $user->id; - // Retrieve from database: - $tagTable = $this->getTable('Tags'); - $tags = $tagTable->getForResource( - $this->params()->fromQuery('id'), - $this->params()->fromQuery('source', DEFAULT_SEARCH_BACKEND), - 0, null, null, 'count', $is_me_id - ); - - // Build data structure for return: - $tagList = []; - foreach ($tags as $tag) { - $tagList[] = [ - 'tag' => $tag->tag, - 'cnt' => $tag->cnt, - 'is_me' => !empty($tag->is_me) - ]; - } - - // Set layout to render content only: - $this->layout()->setTemplate('layout/lightbox'); - $view = $this->createViewModel( - [ - 'tagList' => $tagList, - 'loggedin' => null !== $user - ] - ); - $view->setTemplate('record/taglist'); - return $view; - } - - /** - * Get record for integrated list view. - * - * @return \Zend\Http\Response - */ - protected function getRecordDetailsAjax() - { - $driver = $this->getRecordLoader()->load( - $this->params()->fromQuery('id'), - $this->params()->fromQuery('source') - ); - $viewtype = preg_replace( - '/\W/', '', - trim(strtolower($this->params()->fromQuery('type'))) - ); - $request = $this->getRequest(); - $config = $this->serviceLocator->get('Config'); - - $recordTabPlugin = $this->serviceLocator - ->get('VuFind\RecordTab\PluginManager'); - $details = $recordTabPlugin - ->getTabDetailsForRecord( - $driver, - $config['vufind']['recorddriver_tabs'], - $request, - 'Information' - ); - - $rtpm = $this->serviceLocator->get('VuFind\RecordTab\PluginManager'); - $html = $this->getViewRenderer() - ->render( - "record/ajaxview-" . $viewtype . ".phtml", - [ - 'defaultTab' => $details['default'], - 'driver' => $driver, - 'tabs' => $details['tabs'], - 'backgroundTabs' => $rtpm->getBackgroundTabNames( - $driver, $this->getRecordTabConfig() - ) - ] - ); - return $this->output($html, self::STATUS_OK); - } - - /** - * AJAX for timeline feature (PubDateVisAjax) - * - * @param array $fields Solr fields to retrieve data from - * - * @author Chris Hallberg <crhallberg@gmail.com> - * @author Till Kinstler <kinstler@gbv.de> - * - * @return \Zend\Http\Response - */ - protected function getVisDataAjax($fields = ['publishDate']) - { - $this->disableSessionWrites(); // avoid session write timing bug - $results = $this->getResultsManager()->get('Solr'); - $params = $results->getParams(); - $params->initFromRequest($this->getRequest()->getQuery()); - foreach ($this->params()->fromQuery('hf', []) as $hf) { - $params->addHiddenFilter($hf); - } - $params->getOptions()->disableHighlighting(); - $params->getOptions()->spellcheckEnabled(false); - $filters = $params->getFilters(); - $dateFacets = $this->params()->fromQuery('facetFields'); - $dateFacets = empty($dateFacets) ? [] : explode(':', $dateFacets); - $fields = $this->processDateFacets($filters, $dateFacets, $results); - $facets = $this->processFacetValues($fields, $results); - foreach ($fields as $field => $val) { - $facets[$field]['min'] = $val[0] > 0 ? $val[0] : 0; - $facets[$field]['max'] = $val[1] > 0 ? $val[1] : 0; - $facets[$field]['removalURL'] - = $results->getUrlQuery()->removeFacet( - $field, - $filters[$field][0] ?? null - )->getParams(false); - } - return $this->output($facets, self::STATUS_OK); - } - - /** - * Support method for getVisData() -- extract details from applied filters. - * - * @param array $filters Current filter list - * @param array $dateFacets Objects containing the date - * ranges - * @param \VuFind\Search\Solr\Results $results Search results object - * - * @return array - */ - protected function processDateFacets($filters, $dateFacets, $results) - { - $result = []; - foreach ($dateFacets as $current) { - $from = $to = ''; - if (isset($filters[$current])) { - foreach ($filters[$current] as $filter) { - if (preg_match('/\[[\d\*]+ TO [\d\*]+\]/', $filter)) { - $range = explode(' TO ', trim($filter, '[]')); - $from = $range[0] == '*' ? '' : $range[0]; - $to = $range[1] == '*' ? '' : $range[1]; - break; - } - } - } - $result[$current] = [$from, $to]; - $result[$current]['label'] - = $results->getParams()->getFacetLabel($current); - } - return $result; - } - - /** - * Support method for getVisData() -- filter bad values from facet lists. - * - * @param array $fields Processed date information from - * processDateFacets - * @param \VuFind\Search\Solr\Results $results Search results object - * - * @return array - */ - protected function processFacetValues($fields, $results) - { - $facets = $results->getFullFieldFacets(array_keys($fields)); - $retVal = []; - foreach ($facets as $field => $values) { - $newValues = ['data' => []]; - foreach ($values['data']['list'] as $current) { - // Only retain numeric values! - if (preg_match("/^[0-9]+$/", $current['value'])) { - $newValues['data'][] - = [$current['value'], $current['count']]; - } - } - $retVal[$field] = $newValues; - } - return $retVal; - } - - /** - * Get Autocomplete suggestions. - * - * @return \Zend\Http\Response - */ - protected function getACSuggestionsAjax() - { - $this->disableSessionWrites(); // avoid session write timing bug - $query = $this->getRequest()->getQuery(); - $suggester = $this->serviceLocator->get('VuFind\Autocomplete\Suggester'); - return $this->output($suggester->getSuggestions($query), self::STATUS_OK); - } - - /** - * Check Request is Valid - * - * @return \Zend\Http\Response - */ - protected function checkRequestIsValidAjax() - { - $this->disableSessionWrites(); // avoid session write timing bug - $id = $this->params()->fromQuery('id'); - $data = $this->params()->fromQuery('data'); - $requestType = $this->params()->fromQuery('requestType'); - if (empty($id) || empty($data)) { - return $this->output( - $this->translate('bulk_error_missing'), - self::STATUS_ERROR, - 400 - ); - } - // check if user is logged in - $user = $this->getUser(); - if (!$user) { - return $this->output( - $this->translate('You must be logged in first'), - self::STATUS_NEED_AUTH, - 401 - ); - } - - try { - $catalog = $this->getILS(); - $patron = $this->getILSAuthenticator()->storedCatalogLogin(); - if ($patron) { - switch ($requestType) { - case 'ILLRequest': - $results = $catalog->checkILLRequestIsValid($id, $data, $patron); - if (is_array($results)) { - $msg = $results['status']; - $results = $results['valid']; - } else { - $msg = $results - ? 'ill_request_place_text' : 'ill_request_error_blocked'; - } - break; - case 'StorageRetrievalRequest': - $results = $catalog->checkStorageRetrievalRequestIsValid( - $id, $data, $patron - ); - if (is_array($results)) { - $msg = $results['status']; - $results = $results['valid']; - } else { - $msg = $results ? 'storage_retrieval_request_place_text' - : 'storage_retrieval_request_error_blocked'; - } - break; - default: - $results = $catalog->checkRequestIsValid($id, $data, $patron); - if (is_array($results)) { - $msg = $results['status']; - $results = $results['valid']; - } else { - $msg = $results ? 'request_place_text' - : 'hold_error_blocked'; - break; - } - } - return $this->output( - ['status' => $results, 'msg' => $this->translate($msg)], - self::STATUS_OK - ); - } - } catch (\Exception $e) { - // Do nothing -- just fail through to the error message below. - } - - return $this->output( - $this->translate('An error has occurred'), self::STATUS_ERROR, 500 - ); - } - - /** - * Comment on a record. - * - * @return \Zend\Http\Response - */ - protected function commentRecordAjax() - { - // Make sure comments are enabled: - if (!$this->commentsEnabled()) { - return $this->output( - $this->translate('Comments disabled'), - self::STATUS_ERROR, - 403 - ); - } - - $user = $this->getUser(); - if ($user === false) { - return $this->output( - $this->translate('You must be logged in first'), - self::STATUS_NEED_AUTH, - 401 - ); - } - - $id = $this->params()->fromPost('id'); - $comment = $this->params()->fromPost('comment'); - if (empty($id) || empty($comment)) { - return $this->output( - $this->translate('bulk_error_missing'), - self::STATUS_ERROR, - 400 - ); - } - - $useCaptcha = $this->recaptcha()->active('userComments'); - $this->recaptcha()->setErrorMode('none'); - if (!$this->formWasSubmitted('comment', $useCaptcha)) { - return $this->output( - $this->translate('recaptcha_not_passed'), - self::STATUS_ERROR, - 403 - ); - } - - $table = $this->getTable('Resource'); - $resource = $table->findResource( - $id, $this->params()->fromPost('source', DEFAULT_SEARCH_BACKEND) - ); - $id = $resource->addComment($comment, $user); - - return $this->output($id, self::STATUS_OK); - } - - /** - * Delete a comment on a record. - * - * @return \Zend\Http\Response - */ - protected function deleteRecordCommentAjax() - { - // Make sure comments are enabled: - if (!$this->commentsEnabled()) { - return $this->output( - $this->translate('Comments disabled'), - self::STATUS_ERROR, - 403 - ); - } - - $user = $this->getUser(); - if ($user === false) { - return $this->output( - $this->translate('You must be logged in first'), - self::STATUS_NEED_AUTH, - 401 - ); - } - - $id = $this->params()->fromQuery('id'); - if (empty($id)) { - return $this->output( - $this->translate('bulk_error_missing'), - self::STATUS_ERROR, - 400 - ); - } - $table = $this->getTable('Comments'); - if (!$table->deleteIfOwnedByUser($id, $user)) { - return $this->output( - $this->translate('edit_list_fail'), - self::STATUS_ERROR, - 403 - ); - } - - return $this->output($this->translate('Done'), self::STATUS_OK); - } - - /** - * Get list of comments for a record as HTML. - * - * @return \Zend\Http\Response - */ - protected function getRecordCommentsAsHTMLAjax() - { - $driver = $this->getRecordLoader()->load( - $this->params()->fromQuery('id'), - $this->params()->fromQuery('source', DEFAULT_SEARCH_BACKEND) - ); - $html = $this->getViewRenderer() - ->render('record/comments-list.phtml', ['driver' => $driver]); - return $this->output($html, self::STATUS_OK); - } - - /** - * Fetch Links from resolver given an OpenURL and format as HTML - * and output the HTML content in JSON object. - * - * @return \Zend\Http\Response - * @author Graham Seaman <Graham.Seaman@rhul.ac.uk> - */ - protected function getResolverLinksAjax() - { - $this->disableSessionWrites(); // avoid session write timing bug - $openUrl = $this->params()->fromQuery('openurl', ''); - $searchClassId = $this->params()->fromQuery('searchClassId', ''); - - $config = $this->getConfig(); - $resolverType = isset($config->OpenURL->resolver) - ? $config->OpenURL->resolver : 'other'; - $pluginManager = $this->serviceLocator - ->get('VuFind\Resolver\Driver\PluginManager'); - if (!$pluginManager->has($resolverType)) { - return $this->output( - $this->translate("Could not load driver for $resolverType"), - self::STATUS_ERROR, - 500 - ); - } - $resolver = new \VuFind\Resolver\Connection( - $pluginManager->get($resolverType) - ); - if (isset($config->OpenURL->resolver_cache)) { - $resolver->enableCache($config->OpenURL->resolver_cache); - } - $result = $resolver->fetchLinks($openUrl); - - // Sort the returned links into categories based on service type: - $electronic = $print = $services = []; - foreach ($result as $link) { - switch ($link['service_type'] ?? '') { - case 'getHolding': - $print[] = $link; - break; - case 'getWebService': - $services[] = $link; - break; - case 'getDOI': - // Special case -- modify DOI text for special display: - $link['title'] = $this->translate('Get full text'); - $link['coverage'] = ''; - case 'getFullTxt': - default: - $electronic[] = $link; - break; - } - } - - // Get the OpenURL base: - if (isset($config->OpenURL) && isset($config->OpenURL->url)) { - // Trim off any parameters (for legacy compatibility -- default config - // used to include extraneous parameters): - list($base) = explode('?', $config->OpenURL->url); - } else { - $base = false; - } - - $moreOptionsLink = $resolver->supportsMoreOptionsLink() - ? $resolver->getResolverUrl($openUrl) : ''; - - // Render the links using the view: - $view = [ - 'openUrlBase' => $base, 'openUrl' => $openUrl, 'print' => $print, - 'electronic' => $electronic, 'services' => $services, - 'searchClassId' => $searchClassId, - 'moreOptionsLink' => $moreOptionsLink - ]; - $html = $this->getViewRenderer()->render('ajax/resolverLinks.phtml', $view); - - // output HTML encoded in JSON object - return $this->output($html, self::STATUS_OK); - } - - /** - * Keep Alive - * - * This is responsible for keeping the session alive whenever called - * (via JavaScript) - * - * @return \Zend\Http\Response - */ - protected function keepAliveAjax() - { - // Request ID from session to mark it active - $this->serviceLocator->get('Zend\Session\SessionManager')->getId(); - return $this->output(true, self::STATUS_OK); - } - - /** - * Get pick up locations for a library - * - * @return \Zend\Http\Response - */ - protected function getLibraryPickupLocationsAjax() - { - $this->disableSessionWrites(); // avoid session write timing bug - $id = $this->params()->fromQuery('id'); - $pickupLib = $this->params()->fromQuery('pickupLib'); - if (null === $id || null === $pickupLib) { - return $this->output( - $this->translate('bulk_error_missing'), - self::STATUS_ERROR, - 400 - ); - } - // check if user is logged in - $user = $this->getUser(); - if (!$user) { - return $this->output( - $this->translate('You must be logged in first'), - self::STATUS_NEED_AUTH, - 401 - ); - } - - try { - $catalog = $this->getILS(); - $patron = $this->getILSAuthenticator()->storedCatalogLogin(); - if ($patron) { - $results = $catalog->getILLPickupLocations($id, $pickupLib, $patron); - foreach ($results as &$result) { - if (isset($result['name'])) { - $result['name'] = $this->translate( - 'location_' . $result['name'], - [], - $result['name'] - ); - } - } - return $this->output(['locations' => $results], self::STATUS_OK); - } - } catch (\Exception $e) { - // Do nothing -- just fail through to the error message below. - } - - return $this->output( - $this->translate('An error has occurred'), self::STATUS_ERROR, 500 - ); - } - - /** - * Get pick up locations for a request group - * - * @return \Zend\Http\Response - */ - protected function getRequestGroupPickupLocationsAjax() - { - $this->disableSessionWrites(); // avoid session write timing bug - $id = $this->params()->fromQuery('id'); - $requestGroupId = $this->params()->fromQuery('requestGroupId'); - if (null === $id || null === $requestGroupId) { - return $this->output( - $this->translate('bulk_error_missing'), - self::STATUS_ERROR, - 400 - ); - } - // check if user is logged in - $user = $this->getUser(); - if (!$user) { - return $this->output( - $this->translate('You must be logged in first'), - self::STATUS_NEED_AUTH, - 401 - ); - } - - try { - $catalog = $this->getILS(); - $patron = $this->getILSAuthenticator()->storedCatalogLogin(); - if ($patron) { - $details = [ - 'id' => $id, - 'requestGroupId' => $requestGroupId - ]; - $results = $catalog->getPickupLocations($patron, $details); - foreach ($results as &$result) { - if (isset($result['locationDisplay'])) { - $result['locationDisplay'] = $this->translate( - 'location_' . $result['locationDisplay'], - [], - $result['locationDisplay'] - ); - } - } - return $this->output(['locations' => $results], self::STATUS_OK); - } - } catch (\Exception $e) { - // Do nothing -- just fail through to the error message below. - } - - return $this->output( - $this->translate('An error has occurred'), self::STATUS_ERROR, 500 - ); - } - - /** - * Get hierarchical facet data for jsTree - * - * Parameters: - * facetName The facet to retrieve - * facetSort By default all facets are sorted by count. Two values are available - * for alternative sorting: - * top = sort the top level alphabetically, rest by count - * all = sort all levels alphabetically - * - * @return \Zend\Http\Response - */ - protected function getFacetDataAjax() - { - $this->disableSessionWrites(); // avoid session write timing bug - - $facet = $this->params()->fromQuery('facetName'); - $sort = $this->params()->fromQuery('facetSort'); - $operator = $this->params()->fromQuery('facetOperator'); - - $results = $this->getResultsManager()->get('Solr'); - $params = $results->getParams(); - $params->addFacet($facet, null, $operator === 'OR'); - $params->initFromRequest($this->getRequest()->getQuery()); - - $facets = $results->getFullFieldFacets([$facet], false, -1, 'count'); - if (empty($facets[$facet]['data']['list'])) { - return $this->output([], self::STATUS_OK); - } - - $facetList = $facets[$facet]['data']['list']; - - $facetHelper = $this->serviceLocator - ->get('VuFind\Search\Solr\HierarchicalFacetHelper'); - if (!empty($sort)) { - $facetHelper->sortFacetList($facetList, $sort == 'top'); - } - - return $this->output( - $facetHelper->buildFacetArray( - $facet, $facetList, $results->getUrlQuery() - ), - self::STATUS_OK - ); + return $this->callAjaxMethod('recommend', 'text/html'); } /** @@ -1318,83 +85,8 @@ class AjaxController extends AbstractBase * * @return \Zend\Http\Response */ - protected function systemStatusAction() - { - $this->outputMode = 'plaintext'; - - // Check system status - $config = $this->getConfig(); - if (!empty($config->System->healthCheckFile) - && file_exists($config->System->healthCheckFile) - ) { - return $this->output( - 'Health check file exists', self::STATUS_ERROR, 503 - ); - } - - // Test search index - try { - $results = $this->getResultsManager()->get('Solr'); - $params = $results->getParams(); - $params->setQueryIDs(['healthcheck']); - $results->performAndProcessSearch(); - } catch (\Exception $e) { - return $this->output( - 'Search index error: ' . $e->getMessage(), self::STATUS_ERROR, 500 - ); - } - - // Test database connection - try { - $sessionTable = $this->getTable('Session'); - $sessionTable->getBySessionId('healthcheck', false); - } catch (\Exception $e) { - return $this->output( - 'Database error: ' . $e->getMessage(), self::STATUS_ERROR, 500 - ); - } - - // This may be called frequently, don't leave sessions dangling - $this->serviceLocator->get('Zend\Session\SessionManager')->destroy(); - - return $this->output('', self::STATUS_OK); - } - - /** - * Convenience method for accessing results - * - * @return \VuFind\Search\Results\PluginManager - */ - protected function getResultsManager() - { - return $this->serviceLocator->get('VuFind\Search\Results\PluginManager'); - } - - /** - * Get Ils Status - * - * This will check the ILS for being online and will return the ils-offline - * template upon failure. - * - * @return \Zend\Http\Response - * @author André Lahmann <lahmann@ub.uni-leipzig.de> - */ - protected function getIlsStatusAjax() + public function systemStatusAction() { - $this->disableSessionWrites(); // avoid session write timing bug - if ($this->getILS()->getOfflineMode(true) == 'ils-offline') { - $offlineModeMsg = $this->params()->fromPost( - 'offlineModeMsg', - $this->params()->fromQuery('offlineModeMsg') - ); - return $this->output( - $this->getViewRenderer()->render( - 'Helpers/ils-offline.phtml', - compact('offlineModeMsg') - ), - self::STATUS_OK - ); - } - return $this->output('', self::STATUS_OK); + return $this->callAjaxMethod('systemStatus', 'text/plain'); } } diff --git a/module/VuFind/src/VuFind/Controller/AjaxControllerFactory.php b/module/VuFind/src/VuFind/Controller/AjaxControllerFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..ec10195410780fb3523119875594cde8e0c39819 --- /dev/null +++ b/module/VuFind/src/VuFind/Controller/AjaxControllerFactory.php @@ -0,0 +1,67 @@ +<?php +/** + * Ajax controller factory. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package Controller + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\Controller; + +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Factory\FactoryInterface; + +/** + * Ajax controller factory. + * + * @category VuFind + * @package Controller + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class AjaxControllerFactory implements FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options sent to factory.'); + } + $pm = $container->get('VuFind\AjaxHandler\PluginManager'); + return new $requestedName($pm); + } +} diff --git a/module/VuFind/src/VuFind/Controller/AjaxResponseTrait.php b/module/VuFind/src/VuFind/Controller/AjaxResponseTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..3d3c066f88da96cfb09e5ca645b4c9173479db5b --- /dev/null +++ b/module/VuFind/src/VuFind/Controller/AjaxResponseTrait.php @@ -0,0 +1,188 @@ +<?php +/** + * Trait to allow AJAX response generation. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package Controller + * @author Chris Hallberg <challber@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:controllers Wiki + */ +namespace VuFind\Controller; + +use VuFind\AjaxHandler\AjaxHandlerInterface as Ajax; +use VuFind\AjaxHandler\PluginManager; + +/** + * Trait to allow AJAX response generation. + * + * Dependencies: + * - \VuFind\I18n\Translator\TranslatorAwareTrait + * - Injection of $this->ajaxManager (for some functionality) + * + * @category VuFind + * @package Controller + * @author Chris Hallberg <challber@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:controllers Wiki + */ +trait AjaxResponseTrait +{ + /** + * Array of PHP errors captured during execution. Add this code to your + * constructor in order to populate the array: + * set_error_handler([static::class, 'storeError']); + * + * @var array + */ + protected static $php_errors = []; + + /** + * AJAX Handler plugin manager + * + * @var PluginManager; + */ + protected $ajaxManager = null; + + /** + * 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 string $status Status of the request + * + * @return string + * @throws \Exception + */ + protected function formatContent($type, $data, $status) + { + switch ($type) { + case 'application/javascript': + $output = compact('data', 'status'); + if ('development' == APPLICATION_ENV && count(self::$php_errors) > 0) { + $output['php_errors'] = self::$php_errors; + } + return json_encode($output); + case 'text/plain': + return $data ? $status . " $data" : $status; + case 'text/html': + return $data ?: ''; + default: + throw new \Exception("Unsupported content type: $type"); + } + } + + /** + * Send output data and exit. + * + * @param string $type Content type to output + * @param mixed $data The response data + * @param string $status Status of the request + * @param int $httpCode A custom HTTP Status Code + * + * @return \Zend\Http\Response + * @throws \Exception + */ + protected function getAjaxResponse($type, $data, $status = Ajax::STATUS_OK, + $httpCode = null + ) { + $response = $this->getResponse(); + $headers = $response->getHeaders(); + $headers->addHeaderLine('Content-type', $type); + $headers->addHeaderLine('Cache-Control', 'no-cache, must-revalidate'); + $headers->addHeaderLine('Expires', 'Mon, 26 Jul 1997 05:00:00 GMT'); + if ($httpCode !== null) { + $response->setStatusCode($httpCode); + } + $response->setContent($this->formatContent($type, $data, $status)); + return $response; + } + + /** + * Turn an exception into error response. + * + * @param string $type Content type to output + * @param \Exception $e Exception to output. + * + * @return \Zend\Http\Response + */ + protected function getExceptionResponse($type, \Exception $e) + { + $debugMsg = ('development' == APPLICATION_ENV) + ? ': ' . $e->getMessage() : ''; + return $this->getAjaxResponse( + $type, + $this->translate('An error has occurred') . $debugMsg, + Ajax::STATUS_ERROR, + 500 + ); + } + + /** + * Call an AJAX method and turn the result into a response. + * + * @param string $method AJAX method to call + * @param string $type Content type to output + * + * @return \Zend\Http\Response + */ + protected function callAjaxMethod($method, $type = 'application/javascript') + { + // 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); + return $this->getAjaxResponse( + $type, ...$handler->handleRequest($this->params()) + ); + } catch (\Exception $e) { + return $this->getExceptionResponse($type, $e); + } + } + + // If we got this far, we can't handle the requested method: + return $this->getAjaxResponse( + $type, + $this->translate('Invalid Method'), + Ajax::STATUS_ERROR, + 400 + ); + } + + /** + * Store the errors for later, to be added to the output + * + * @param string $errno Error code number + * @param string $errstr Error message + * @param string $errfile File where error occurred + * @param string $errline Line number of error + * + * @return bool Always true to cancel default error handling + */ + public static function storeError($errno, $errstr, $errfile, $errline) + { + self::$php_errors[] = "ERROR [$errno] - " . $errstr . "<br />\n" + . " Occurred in " . $errfile . " on line " . $errline . "."; + return true; + } +} diff --git a/module/VuFind/src/VuFind/Controller/CombinedController.php b/module/VuFind/src/VuFind/Controller/CombinedController.php index 02fb5c01caee808a686c7e07a5d4b8eccce653d6..5566e6df1a81edc1f2253989903813c6eaa0e068 100644 --- a/module/VuFind/src/VuFind/Controller/CombinedController.php +++ b/module/VuFind/src/VuFind/Controller/CombinedController.php @@ -40,6 +40,8 @@ use Zend\ServiceManager\ServiceLocatorInterface; */ class CombinedController extends AbstractSearch { + use AjaxResponseTrait; + /** * Constructor * @@ -94,13 +96,6 @@ class CombinedController extends AbstractSearch $this->adjustQueryForSettings($settings); $settings['view'] = $this->forwardTo($controller, $action); - // Send response: - $response = $this->getResponse(); - $headers = $response->getHeaders(); - $headers->addHeaderLine('Content-type', 'text/html'); - $headers->addHeaderLine('Cache-Control', 'no-cache, must-revalidate'); - $headers->addHeaderLine('Expires', 'Mon, 26 Jul 1997 05:00:00 GMT'); - // Should we suppress content due to emptiness? if (isset($settings['hide_if_empty']) && $settings['hide_if_empty'] && $settings['view']->results->getResultTotal() == 0 @@ -127,8 +122,7 @@ class CombinedController extends AbstractSearch $viewParams ); } - $response->setContent($html); - return $response; + return $this->getAjaxResponse('text/html', $html); } /** diff --git a/module/VuFind/src/VuFindTest/Unit/AjaxHandlerTest.php b/module/VuFind/src/VuFindTest/Unit/AjaxHandlerTest.php new file mode 100644 index 0000000000000000000000000000000000000000..e8ddeef1177828c42b4bc28eb9268ba01356587f --- /dev/null +++ b/module/VuFind/src/VuFindTest/Unit/AjaxHandlerTest.php @@ -0,0 +1,123 @@ +<?php +/** + * Base class for AjaxHandler tests. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package Tests + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Page + */ +namespace VuFindTest\Unit; + +use Zend\Http\Request; +use Zend\Mvc\Controller\Plugin\Params; +use Zend\ServiceManager\ServiceManager; +use Zend\Stdlib\Parameters; + +/** + * Base class for AjaxHandler tests. + * + * @category VuFind + * @package Tests + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Page + */ +abstract class AjaxHandlerTest extends \PHPUnit\Framework\TestCase +{ + /** + * Create a mock service. + * + * @param string $name Name of class implementing service + * @param array $methods Methods to mock + * + * @return object + */ + protected function getMockService($name, $methods = []) + { + return $this->getMockBuilder($name) + ->disableOriginalConstructor() + ->setMethods($methods) + ->getMock(); + } + + /** + * Create mock user object. + * + * @return \VuFind\Db\Row\User + */ + protected function getMockUser() + { + return $this->getMockService('VuFind\Db\Row\User'); + } + + /** + * Add a service to a container. + * + * @param ServiceManager $container Container to populate + * @param string $name Name of service to create + * @param mixed $value Value of service (or null to create mock) + * + * @return void + */ + protected function addServiceToContainer($container, $name, $value = null) + { + $container->setService($name, $value ?? $this->getMockService($name)); + } + + /** + * Get an auth manager with a value set for isLoggedIn. + * + * @param \VuFind\Db\Row\User $user Return value for isLoggedIn() + * + * @return \VuFind\Auth\Manager + */ + protected function getMockAuthManager($user) + { + $authManager = $this->getMockService('VuFind\Auth\Manager', ['isLoggedIn']); + $authManager->expects($this->any())->method('isLoggedIn') + ->will($this->returnValue($user)); + return $authManager; + } + + /** + * Build a Params helper for testing. + * + * @param array $get GET parameters + * @param array $post POST parameters + * + * @return Params + */ + protected function getParamsHelper($get = [], $post = []) + { + $params = new Params(); + $request = new Request(); + $request->setQuery(new Parameters($get)); + $request->setPost(new Parameters($post)); + $controller = $this->getMockService( + 'Zend\Mvc\Controller\AbstractActionController', ['getRequest'] + ); + $controller->expects($this->any())->method('getRequest') + ->will($this->returnValue($request)); + $params->setController($controller); + return $params; + } +} diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/AjaxHandler/CheckRequestIsValidTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/AjaxHandler/CheckRequestIsValidTest.php new file mode 100644 index 0000000000000000000000000000000000000000..e680a81025cfc886c4de4faae76e829e5529b115 --- /dev/null +++ b/module/VuFind/tests/unit-tests/src/VuFindTest/AjaxHandler/CheckRequestIsValidTest.php @@ -0,0 +1,172 @@ +<?php +/** + * CheckRequestIsValid test class. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package Tests + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Page + */ +namespace VuFindTest\AjaxHandler; + +use VuFind\AjaxHandler\AbstractIlsAndUserActionFactory; +use VuFind\AjaxHandler\CheckRequestIsValid; +use VuFind\Auth\ILSAuthenticator; +use VuFind\ILS\Connection; +use VuFind\Session\Settings; +use Zend\ServiceManager\ServiceManager; + +/** + * CheckRequestIsValid test class. + * + * @category VuFind + * @package Tests + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Page + */ +class CheckRequestIsValidTest extends \VuFindTest\Unit\AjaxHandlerTest +{ + /** + * Set up a CheckRequestIsValid handler for testing. + * + * @param Settings $ss Session settings (or null for default) + * @param Connection $ils ILS connection (or null for default) + * @param ILSAuthenticator $ilsAuth ILS authenticator (or null for default) + * @param User|bool $user Return value for isLoggedIn() in auth manager + * + * @return CheckRequestIsValid + */ + protected function getHandler($ss = null, $ils = null, $ilsAuth = null, + $user = false + ) { + // Create container + $container = new ServiceManager(); + + // Install or mock up services: + $this->addServiceToContainer($container, 'VuFind\Session\Settings', $ss); + $this->addServiceToContainer($container, 'VuFind\ILS\Connection', $ils); + $this->addServiceToContainer( + $container, 'VuFind\Auth\ILSAuthenticator', $ilsAuth + ); + + // Set up auth manager with user: + $authManager = $this->getMockAuthManager($user); + $container->setService('VuFind\Auth\Manager', $authManager); + + // Build the handler: + $factory = new AbstractIlsAndUserActionFactory(); + return $factory($container, CheckRequestIsValid::class); + } + + /** + * Test the AJAX handler's response when no one is logged in. + * + * @return void + */ + public function testLoggedOutUser() + { + $handler = $this->getHandler(); + $this->assertEquals( + ['You must be logged in first', 'NEED_AUTH', 401], + $handler->handleRequest($this->getParamsHelper(['id' => 1, 'data' => 1])) + ); + } + + /** + * Test the AJAX handler's response when the query is empty. + * + * @return void + */ + public function testEmptyQuery() + { + $handler = $this->getHandler(null, null, null, $this->getMockUser()); + $this->assertEquals( + ['bulk_error_missing', 'ERROR', 400], + $handler->handleRequest($this->getParamsHelper()) + ); + } + + /** + * Generic support function for successful request tests. + * + * @return void + */ + protected function runSuccessfulTest($ilsMethod, $requestType = null) + { + $ilsAuth = $this->getMockService( + 'VuFind\Auth\ILSAuthenticator', ['storedCatalogLogin'] + ); + $ilsAuth->expects($this->once())->method('storedCatalogLogin') + ->will($this->returnValue([3])); + $ils = $this + ->getMockService('VuFind\ILS\Connection', [$ilsMethod]); + $ils->expects($this->once())->method($ilsMethod) + ->with($this->equalTo(1), $this->equalTo(2), $this->equalTo([3])) + ->will($this->returnValue(true)); + $handler = $this->getHandler(null, $ils, $ilsAuth, $this->getMockUser()); + $params = ['id' => 1, 'data' => 2, 'requestType' => $requestType]; + return $handler->handleRequest($this->getParamsHelper($params)); + } + + /** + * Test a successful hold response. + * + * @return void + */ + public function testHoldResponse() + { + $this->assertEquals( + [['status' => true, 'msg' => 'request_place_text'], 'OK'], + $this->runSuccessfulTest('checkRequestIsValid') + ); + } + + /** + * Test a successful ILL response. + * + * @return void + */ + public function testILLResponse() + { + $this->assertEquals( + [['status' => true, 'msg' => 'ill_request_place_text'], 'OK'], + $this->runSuccessfulTest('checkILLRequestIsValid', 'ILLRequest') + ); + } + + /** + * Test a successful storage retrieval response. + * + * @return void + */ + public function testStorageResponse() + { + $this->assertEquals( + [ + ['status' => true, 'msg' => 'storage_retrieval_request_place_text'], + 'OK' + ], $this->runSuccessfulTest( + 'checkStorageRetrievalRequestIsValid', 'StorageRetrievalRequest' + ) + ); + } +} diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/AjaxHandler/CommentRecordTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/AjaxHandler/CommentRecordTest.php new file mode 100644 index 0000000000000000000000000000000000000000..22eaad9f48ba9b24658bc9197aaa16844f2bfac9 --- /dev/null +++ b/module/VuFind/tests/unit-tests/src/VuFindTest/AjaxHandler/CommentRecordTest.php @@ -0,0 +1,175 @@ +<?php +/** + * CommentRecord test class. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package Tests + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Page + */ +namespace VuFindTest\AjaxHandler; + +use VuFind\AjaxHandler\CommentRecord; +use VuFind\AjaxHandler\CommentRecordFactory; +use VuFind\Controller\Plugin\Recaptcha; +use VuFind\Db\Row\Resource; +use VuFind\Db\Row\User; +use VuFind\Db\Table\Resource as ResourceTable; +use Zend\ServiceManager\ServiceManager; + +/** + * CommentRecord test class. + * + * @category VuFind + * @package Tests + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Page + */ +class CommentRecordTest extends \VuFindTest\Unit\AjaxHandlerTest +{ + /** + * Set up a CommentRecord handler for testing. + * + * @param ResourceTable $table Resource table mock (or null for default) + * @param Recaptcha $recaptcha Recaptcha plugin mock (or null for default) + * @param bool $enabled Are comments enabled? + * @param User|bool $user Return value for isLoggedIn() in auth manager + * + * @return CommentRecord + */ + protected function getHandler($table = null, $recaptcha = null, $enabled = true, + $user = false + ) { + // Create container + $container = new ServiceManager(); + + // For simplicity, let the top-level container stand in for the plugin + // managers: + $container->setService('VuFind\Db\Table\PluginManager', $container); + $container->setService('ControllerPluginManager', $container); + + // Install or mock up remaining services: + $this->addServiceToContainer( + $container, 'VuFind\Db\Table\Resource', $table + ); + $this->addServiceToContainer( + $container, 'VuFind\Controller\Plugin\Recaptcha', $recaptcha + ); + + // Set up auth manager with user: + $authManager = $this->getMockAuthManager($user); + $container->setService('VuFind\Auth\Manager', $authManager); + + // Set up capability configuration: + $cfg = new \Zend\Config\Config( + ['Social' => ['comments' => $enabled ? 'enabled' : 'disabled']] + ); + $capabilities = new \VuFind\Config\AccountCapabilities($cfg, $authManager); + $container->setService('VuFind\Config\AccountCapabilities', $capabilities); + + // Build the handler: + $factory = new CommentRecordFactory(); + return $factory($container, CommentRecord::class); + } + + /** + * Return a mock resource row that expects a specific user and comment. + * + * @param string $comment Comment to expect + * @param User $user User to expect + * + * @return Resource + */ + protected function getMockResource($comment, $user) + { + $row = $this->getMockService('VuFind\Db\Row\Resource', ['addComment']); + $row->expects($this->once())->method('addComment') + ->with($this->equalTo($comment), $this->equalTo($user)) + ->will($this->returnValue(true)); + return $row; + } + + /** + * Test the AJAX handler's response when comments are disabled. + * + * @return void + */ + public function testDisabledResponse() + { + $handler = $this->getHandler(null, null, false); + $this->assertEquals( + ['Comments disabled', 'ERROR', 403], + $handler->handleRequest($this->getParamsHelper()) + ); + } + + /** + * Test the AJAX handler's response when no one is logged in. + * + * @return void + */ + public function testLoggedOutUser() + { + $handler = $this->getHandler(null, null, true); + $this->assertEquals( + ['You must be logged in first', 'NEED_AUTH', 401], + $handler->handleRequest($this->getParamsHelper()) + ); + } + + /** + * Test the AJAX handler's response when the query is empty. + * + * @return void + */ + public function testEmptyQuery() + { + $handler = $this->getHandler(null, null, true, $this->getMockUser()); + $this->assertEquals( + ['bulk_error_missing', 'ERROR', 400], + $handler->handleRequest($this->getParamsHelper()) + ); + } + + /** + * Test a successful scenario. + * + * @return void + */ + public function testSuccessfulTransaction() + { + $user = $this->getMockUser(); + $table = $this->getMockService('VuFind\Db\Table\Resource', ['findResource']); + $table->expects($this->once())->method('findResource') + ->with($this->equalTo('foo'), $this->equalTo('Solr')) + ->will($this->returnValue($this->getMockResource('bar', $user))); + $handler = $this->getHandler($table, null, true, $user); + $post = [ + 'id' => 'foo', + 'comment' => 'bar', + ]; + $this->assertEquals( + [true, 'OK'], + $handler->handleRequest($this->getParamsHelper([], $post)) + ); + } +} diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/AjaxHandler/KeepAliveTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/AjaxHandler/KeepAliveTest.php new file mode 100644 index 0000000000000000000000000000000000000000..aaf28ca538252d443ae7f0a3957d6409fa2444c9 --- /dev/null +++ b/module/VuFind/tests/unit-tests/src/VuFindTest/AjaxHandler/KeepAliveTest.php @@ -0,0 +1,60 @@ +<?php +/** + * ChoiceAuth test class. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package Tests + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Page + */ +namespace VuFindTest\AjaxHandler; + +use VuFind\AjaxHandler\KeepAlive; +use VuFind\AjaxHandler\KeepAliveFactory; + +/** + * ChoiceAuth test class. + * + * @category VuFind + * @package Tests + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Page + */ +class KeepAliveTest extends \VuFindTest\Unit\AjaxHandlerTest +{ + /** + * Test the AJAX handler's basic response. + * + * @return void + */ + public function testResponse() + { + $sm = $this->getMockService('Zend\Session\SessionManager', ['getId']); + $sm->expects($this->once())->method('getId'); + $container = new \Zend\ServiceManager\ServiceManager(); + $container->setService('Zend\Session\SessionManager', $sm); + $factory = new KeepAliveFactory(); + $handler = $factory($container, KeepAlive::class); + $params = new \Zend\Mvc\Controller\Plugin\Params(); + $this->assertEquals([true, 'OK'], $handler->handleRequest($params)); + } +} diff --git a/themes/bootstrap3/js/record.js b/themes/bootstrap3/js/record.js index 10abb8eaefb53788f451dfb339e65e08fc26ca8b..96d7be709142455ee1e4bc304b82ec845ae4d8b8 100644 --- a/themes/bootstrap3/js/record.js +++ b/themes/bootstrap3/js/record.js @@ -198,12 +198,12 @@ function refreshTagList(_target, _loggedin) { source: recordSource }); $.ajax({ - dataType: 'html', + dataType: 'json', url: url }) .done(function getRecordTagsDone(response) { $tagList.empty(); - $tagList.replaceWith(response); + $tagList.replaceWith(response.data); if (loggedin) { $tagList.addClass('loggedin'); } else {