Skip to content
Snippets Groups Projects
OrderController.php 14.2 KiB
Newer Older
<?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;
    }
}