<?php /** * PHP version 7 * * Copyright (C) 2022 Leipzig University Library * * 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 Dorian Merz <merz@ub.uni-leipzig.de> * @license http://opensource.org/licenses/gpl-2.0.php GNU GPLv2 * @link https://vufind.org/wiki/development Wiki */ namespace fid\Controller; use fid\Hydrator\OrderExportHydrator as OrderExportHydrator; use fid\Service\Client; use fid\Service\ClientException; use fid\Service\DataTransferObject\Order; use fid\Service\UserNotAuthorizedException; use VuFind\Auth\Manager as AuthManager; use VuFind\Controller\AbstractBase; use Zend\Form\Element\Select; use Zend\Form\Form; use Zend\Http\PhpEnvironment\Request; use Zend\Http\PhpEnvironment\Response as HttpResponse; use Zend\Http\Response; use Zend\Mvc\Plugin\FlashMessenger\FlashMessenger; use Zend\ServiceManager\ServiceLocatorInterface; use Zend\View\Model\ViewModel; /** * User Controller * * @category VuFind * @package Controller * @author Dorian Merz <merz@ub.uni-leipzig.de> * @license http://opensource.org/licenses/gpl-2.0.php GNU GPLv2 * @link https://vufind.org/wiki/development Wiki */ class OrderController extends AbstractBase { /** * AuthManager * * @var AuthManager */ protected $authManager; /** * Fidis client * * @var Client */ protected $client; /** * Configuration * * @var array */ protected $config; /** * RegistrationController constructor. * * @param ServiceLocatorInterface $serviceLocator Service Locator * @param AuthManager $authManager Authentication Manager * @param Client $client fidis client * @param array $config Configuration */ public function __construct( ServiceLocatorInterface $serviceLocator, AuthManager $authManager, Client $client, array $config ) { parent::__construct($serviceLocator); $this->authManager = $authManager; $this->client = $client; $this->config = $config; } /** * Get flash messenger * * @return FlashMessenger */ protected function getMessenger(): FlashMessenger { /* @noinspection PhpUndefinedMethodInspection */ /* @var FlashMessenger $messenger */ return $this->flashMessenger(); } /** * Display users order list route action * * @return mixed|void|ViewModel * @throws UserNotAuthorizedException */ public function ordersAction() { if (!$this->getUser()) { return $this->forceLogin(); } try { $user = $this->client->requestUserDetails(null, true); $viewModel = $this->createViewModel(); $orders = $user->getOrders(); $displayCols = $this->config['OrderListUser']['displayCols']; $viewModel->setVariables(compact('orders', 'displayCols')); $viewModel->setTemplate('fid/order/order-list'); return $viewModel; } catch (ClientException $exception) { $this->getMessenger()->addErrorMessage('fid::orders_error'); $this->redirect()->toRoute('myresearch-profile'); } } /** * Edit single order route action * * @return mixed|Response|ViewModel * @throws \Exception */ public function editOrderAction() { if (!$this->getUser()) { return $this->forceLogin(); } /* @var Request $request */ $request = $this->getRequest(); $orderId = $this->params()->fromRoute('orderid'); if (empty($orderId)) { // if no order ID is set the call is not valid return $this->redirect()->toRoute('fid/admin/orders'); } try { $this->permission()->check('fid.EditOrder', 'exception'); $order = $this->client->requestOrder($orderId); } catch (\Exception $ex) { $this->getMessenger() ->addErrorMessage($this->translate('fid::edit_order_error')); return $this->redirect()->toRoute('fid/admin/orders'); } $recordId = $order->getRecordId(); $driver = $recordId ? $this->getRecordLoader()->load($recordId) : null; /* create form only if order type has form configuration in fid.ini */ if (isset($this->config[$order->getType() . "Edit"]['form'])) { /* @var Form $form */ /* @var Select $statusElement */ $form = $this->serviceLocator->get( 'order-edit-form-' . $this->config[$order->getType() . "Edit"]['form'] ); $this->applyStatusOptions($form, $order->getType()); if ($this->formWasSubmitted()) { $form->setData($request->getPost()); if ($form->isValid()) { return $this->updateOrder($form, $order); } } else { $form->setData($form->getHydrator()->extract($order)); } $action = $this->url()->fromRoute( 'fid/admin/editOrder', [ 'orderid' => $order->getId() ] ); $form->setAttribute('action', $action); $form->prepare(); } else { $form = null; } $config = $this->config; $viewModel = $this->createViewModel(); $viewModel->setVariables(compact('config', 'form', 'order', 'driver')); $viewModel->setTemplate('fid/order/order-edit'); return $viewModel; } /** * Update order via fidis and redirect to order list * * @param Form $form Formular * @param \fid\Service\DataTransferObject\Order $order Order object * * @return Response */ protected function updateOrder(Form $form, Order $order) { $data = $form->getData(); $messenger = $this->getMessenger(); try { $form->getHydrator()->hydrate($data, $order); $this->client->requestOrderUpdate($order); $message = $this->translate('fid::order_update_success'); $messenger->addSuccessMessage($message); } catch (\Exception $ex) { $message = $this->translate('fid::order_update_error'); $messenger->addErrorMessage($message); } return $this->redirect()->toRoute('fid/admin/orders'); } /** * Helper method for generating status options list and * applies it to update order status input element. * Display only options stored in configuration. * * @param Form $form Formular * @param string $type Acquisition type * * @return void */ protected function applyStatusOptions($form, $type) { if ($statusOptions = $this->config["{$type}Edit"]['statusOptions'] ?? null) { $options = []; foreach ($statusOptions as $statusOption) { $options[] = [ 'value' => $statusOption, 'label' => $this->translate('fid::status_' . $statusOption), ]; } $statusElement = $form->get('status'); $statusElement->setValueOptions($options); } } /** * Deletes given Order * * @return mixed|void|ViewModel * * @throws UserNotAuthorizedException * @throws ClientException */ public function deleteOrderAction() { if (!$this->getUser()) { return $this->forceLogin(); } $messenger = $this->getMessenger(); try { $orderId = $this->params()->fromRoute('orderid'); $this->client->requestOrderDelete($orderId); $message = $this->translate('fid::order_delete_success'); $messenger->addSuccessMessage($message); } catch (UserNotAuthorizedException $exception) { $messenger->addErrorMessage('fid::read_order_list_not_allowed'); } catch (ClientException $exception) { $messenger->addErrorMessage('fid::order_delete_error'); } return $this->redirect()->toRoute('fid/admin/orders'); } /** * Display admins order list route action * * @return mixed|void|ViewModel */ public function adminOrdersAction() { if (!$this->getUser()) { return $this->forceLogin(); } try { $orders = $this->client->requestOrderList(); $viewModel = $this->createViewModel(); $displayCols = $this->config['OrderListAdmin']['displayCols']; $export_button = $this->config['OrderListAdmin']['export'] ?? false; if ($export_button) { $viewModel->setVariable("export_button", $export_button); } $viewModel->setVariables(compact('orders', 'displayCols')); $viewModel->setTemplate('fid/order/order-list-admin'); return $viewModel; } catch (UserNotAuthorizedException $exception) { $this->getMessenger() ->addErrorMessage('fid::read_order_list_not_allowed'); } catch (ClientException $exception) { $this->getMessenger()->addErrorMessage('fid::read_order_list_error'); $this->redirect()->toRoute('myresearch-profile'); } } /** * Request download of user list route action * * @return HttpResponse * @throws ClientException * @throws UserNotAuthorizedException */ public function exportAction() { $mode = $this->params()->fromRoute('mode') ?? 'default'; $orders = $this->client->requestOrderList(); if ($mode == "json") { return $this->createJsonExportFile($orders); } else { $fields = $this->config['Admin']['order_export_fields'] ?? null; return $this->createCsvExportFile( $orders, $fields, $mode ); } } /** * Build user list export file * * @param Order[] $orderList User List * @param string[] $fields Fields to render * @param string $mode Type of csv/txt that gets exportet * @param string $separator Separator for CSV * * @return HttpResponse */ protected function createCsvExportFile($orderList, $fields=null, $mode="default", $separator="\t") { $response = new HttpResponse(); $prefix = $this->config['Admin']['order_list_export_file_prefix'] ?? 'export'; if ($mode == "conform" or $mode == "microsoft") { $response->getHeaders()->addHeaders( [ 'Content-Encoding: UTF-8', 'Content-type' => 'text/csv;charset=utf-8', 'Content-Disposition' => 'attachment; filename="' . $prefix . '_' . date('Ymd_His') . '.csv"' ] ); } else { $response->getHeaders()->addHeaders( [ 'Content-Encoding: UTF-8', 'Content-type' => 'text/plain;charset=utf-8', 'Content-Disposition' => 'attachment; filename="' . $prefix . '_' . date('Ymd_His') . '.txt"' ] ); } if ($mode == "microsoft") { $output = "sep=\t\n"; } else { $output = ""; } $hydrator = new OrderExportHydrator(); if (empty($fields)) { $fields = $hydrator::FIELDS; } # header foreach ($fields as $rectangle) { $output .= $this->translate('fid_export_' . $rectangle) . $separator; } $output = rtrim($output, $separator) . "\n"; /* @var Order $order */ foreach ($orderList as $order) { $data = $hydrator->extract($order); foreach ($fields as $rectangle) { # translation drive-by if ($rectangle == "type") { $output .= $this->translate("fid::acquisition_" . $data[$rectangle]) . $separator; } else { $output .= $data[$rectangle] . $separator; } } $output = rtrim($output, $separator) . "\n"; } $response->setContent($output); return $response; } /** * Build user list export file * * @param Order[] $orderList User List * @param string[] $fields Fields to include * * @return HttpResponse */ protected function createJsonExportFile($orderList, $fields=null) { $response = new HttpResponse(); $prefix = $this->config['Admin']['order_list_export_file_prefix'] ?? 'export'; $response->getHeaders()->addHeaders( [ 'Content-Encoding: UTF-8', 'Content-type' => 'application/json;charset=utf-8', 'Content-Disposition' => 'attachment; filename="' . $prefix . '_' . date('Ymd_His') . '.json"' ] ); $output = []; $hydrator = new OrderExportHydrator(); foreach ($orderList as $order) { $data = $hydrator->extract($order); $output[$data['id']] = []; //leave out empty fields foreach ($data as $key => $value) { if (!empty($value) and $key != 'id') { $output[$data['id']][$key] = $value; } } } $response->setContent(json_encode($output, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); return $response; } }