306 lines
9.7 KiB
PHP
306 lines
9.7 KiB
PHP
<?php
|
|
|
|
/**
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; under version 2
|
|
* of the License (non-upgradable).
|
|
*
|
|
* 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.
|
|
*
|
|
* Copyright (c) 2018-2020 (original work) Open Assessment Technologies SA ;
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace oat\taoQtiTestPreviewer\controller;
|
|
|
|
use Exception;
|
|
use common_exception_Error;
|
|
use oat\tao\helpers\Base64;
|
|
use tao_helpers_Http as HttpHelper;
|
|
use oat\taoItems\model\pack\Packer;
|
|
use common_Exception as CommonException;
|
|
use taoItems_models_classes_ItemsService;
|
|
use oat\generis\model\OntologyAwareTrait;
|
|
use tao_actions_ServiceModule as ServiceModule;
|
|
use oat\taoItems\model\media\ItemMediaResolver;
|
|
use oat\taoQtiTestPreviewer\models\ItemPreviewer;
|
|
use oat\tao\model\media\sourceStrategy\HttpSource;
|
|
use oat\tao\model\routing\AnnotationReader\security;
|
|
use common_exception_BadRequest as BadRequestException;
|
|
use taoQtiTest_helpers_TestRunnerUtils as TestRunnerUtils;
|
|
use oat\taoQtiTestPreviewer\models\PreviewLanguageService;
|
|
use common_exception_Unauthorized as UnauthorizedException;
|
|
use common_exception_NotImplemented as NotImplementedException;
|
|
use common_exception_MissingParameter as MissingParameterException;
|
|
use common_exception_NoImplementation as NoImplementationException;
|
|
use common_exception_UserReadableException as UserReadableException;
|
|
use tao_models_classes_FileNotFoundException as FileNotFoundException;
|
|
|
|
/**
|
|
* Class Previewer
|
|
*
|
|
* @package oat\taoQtiTestPreviewer\controller
|
|
*/
|
|
class Previewer extends ServiceModule
|
|
{
|
|
use OntologyAwareTrait;
|
|
|
|
/**
|
|
* Previewer constructor.
|
|
*
|
|
* @security("hide")
|
|
*/
|
|
public function __construct()
|
|
{
|
|
parent::__construct();
|
|
|
|
// Prevent anything to be cached by the client.
|
|
TestRunnerUtils::noHttpClientCache();
|
|
}
|
|
|
|
/**
|
|
* Initializes the delivery session
|
|
*/
|
|
public function init(): void
|
|
{
|
|
$code = 200;
|
|
|
|
try {
|
|
$requestParams = $this->getPsrRequest()->getQueryParams();
|
|
$serviceCallId = $requestParams['serviceCallId'];
|
|
|
|
$response = [
|
|
'success' => $serviceCallId === 'previewer',
|
|
'itemIdentifier' => null,
|
|
'itemData' => null,
|
|
];
|
|
} catch (Exception $e) {
|
|
$response = $this->getErrorResponse($e);
|
|
$code = $this->getErrorCode($e);
|
|
}
|
|
|
|
$this->returnJson($response, $code);
|
|
}
|
|
|
|
/**
|
|
* Provides the definition data and the state for a particular item
|
|
*
|
|
* @param taoItems_models_classes_ItemsService $itemsService
|
|
*/
|
|
public function getItem(taoItems_models_classes_ItemsService $itemsService): void
|
|
{
|
|
$code = 200;
|
|
|
|
try {
|
|
$requestParams = $this->getPsrRequest()->getQueryParams();
|
|
|
|
$itemUri = $requestParams['itemUri'] ?? '';
|
|
$resultId = $requestParams['resultId'] ?? '';
|
|
|
|
$response = [
|
|
'baseUrl' => '',
|
|
'content' => [],
|
|
];
|
|
|
|
// Previewing a result.
|
|
if ($resultId !== '') {
|
|
if (!isset($requestParams['itemDefinition'])) {
|
|
throw new MissingParameterException('itemDefinition', $this->getRequestURI());
|
|
}
|
|
|
|
if (!isset($requestParams['deliveryUri'])) {
|
|
throw new MissingParameterException('deliveryUri', $this->getRequestURI());
|
|
}
|
|
|
|
$itemDefinition = $requestParams['itemDefinition'];
|
|
$delivery = $this->getResource($requestParams['deliveryUri']);
|
|
|
|
/** @var ItemPreviewer $itemPreviewer */
|
|
$itemPreviewer = $this->getServiceLocator()->get(ItemPreviewer::class);
|
|
$itemPreviewer->setServiceLocator($this->getServiceLocator());
|
|
|
|
/** @var PreviewLanguageService $previewLanguageService */
|
|
$previewLanguageService = $this->getServiceLocator()->get(PreviewLanguageService::class);
|
|
$previewLanguage = $previewLanguageService->getPreviewLanguage($delivery->getUri(), $resultId);
|
|
|
|
$response['content'] = $itemPreviewer
|
|
->setItemDefinition($itemDefinition)
|
|
->setUserLanguage($previewLanguage)
|
|
->setDelivery($delivery)
|
|
->loadCompiledItemData();
|
|
|
|
$response['baseUrl'] = $itemPreviewer->getBaseUrl();
|
|
} elseif ($itemUri) {
|
|
$item = $this->getResource($itemUri);
|
|
$lang = $this->getSession()->getDataLanguage();
|
|
|
|
if (!$itemsService->hasItemContent($item, $lang)) {
|
|
$this->returnJson($response, $code);
|
|
return;
|
|
}
|
|
|
|
$packer = new Packer($item, $lang);
|
|
$packer->setServiceLocator($this->getServiceLocator());
|
|
|
|
$itemPack = $packer->pack();
|
|
$response['content'] = $itemPack->JsonSerialize();
|
|
$response['baseUrl'] = _url('asset', null, null, [
|
|
'uri' => $itemUri,
|
|
'path' => '',
|
|
]);
|
|
} else {
|
|
throw new BadRequestException('Either itemUri or resultId needs to be provided.');
|
|
}
|
|
|
|
$response['success'] = true;
|
|
} catch (Exception $e) {
|
|
$response = $this->getErrorResponse($e);
|
|
$code = $this->getErrorCode($e);
|
|
}
|
|
|
|
$this->returnJson($response, $code);
|
|
}
|
|
|
|
/**
|
|
* Gets access to an asset
|
|
*
|
|
* @throws CommonException
|
|
* @throws FileNotFoundException
|
|
* @throws common_exception_Error
|
|
*/
|
|
public function asset(): void
|
|
{
|
|
$requestParams = $this->getPsrRequest()->getQueryParams();
|
|
|
|
$item = $this->getResource($requestParams['uri']);
|
|
$lang = $this->getSession()->getDataLanguage();
|
|
$resolver = new ItemMediaResolver($item, $lang);
|
|
|
|
$asset = $resolver->resolve($requestParams['path']);
|
|
$mediaSource = $asset->getMediaSource();
|
|
$mediaIdentifier = $asset->getMediaIdentifier();
|
|
|
|
if ($mediaSource instanceof HttpSource || Base64::isEncodedImage($mediaIdentifier)) {
|
|
throw new CommonException('Only tao files available for rendering through item preview');
|
|
}
|
|
|
|
$info = $mediaSource->getFileInfo($mediaIdentifier);
|
|
$stream = $mediaSource->getFileStream($mediaIdentifier);
|
|
|
|
HttpHelper::returnStream($stream, $info['mime']);
|
|
}
|
|
|
|
/**
|
|
* Stores the state object and the response set of a particular item
|
|
*/
|
|
public function submitItem(): void
|
|
{
|
|
$code = 200;
|
|
|
|
try {
|
|
$requestParams = $this->getPsrRequest()->getQueryParams();
|
|
$itemUri = $requestParams['itemUri'];
|
|
$jsonPayload = $this->getPayload();
|
|
$response = $this->getItemPreviewer()->processResponses($itemUri, $jsonPayload);
|
|
} catch (Exception $e) {
|
|
$response = $this->getErrorResponse($e);
|
|
$code = $this->getErrorCode($e);
|
|
}
|
|
|
|
$this->returnJson($response, $code);
|
|
}
|
|
|
|
/**
|
|
* Gets an error response array
|
|
*
|
|
* @param Exception $e
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function getErrorResponse(Exception $e): array
|
|
{
|
|
$response = [
|
|
'success' => false,
|
|
'type' => 'error',
|
|
];
|
|
|
|
if ($e instanceof FileNotFoundException) {
|
|
$response['type'] = 'FileNotFound';
|
|
$response['message'] = __('File not found');
|
|
} elseif ($e instanceof UnauthorizedException) {
|
|
$response['code'] = 403;
|
|
$response['message'] = $e->getUserMessage();
|
|
} elseif ($e instanceof UserReadableException) {
|
|
$response['message'] = $e->getUserMessage();
|
|
} elseif ($e instanceof Exception) {
|
|
$response['type'] = 'exception';
|
|
$response['code'] = $e->getCode();
|
|
$response['message'] = $e->getMessage();
|
|
} else {
|
|
$response['message'] = __('An error occurred!');
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
|
|
/**
|
|
* Gets an HTTP response code
|
|
*
|
|
* @param Exception $e
|
|
*
|
|
* @return int
|
|
*/
|
|
protected function getErrorCode(Exception $e): int
|
|
{
|
|
switch (true) {
|
|
case $e instanceof NotImplementedException:
|
|
case $e instanceof NoImplementationException:
|
|
case $e instanceof UnauthorizedException:
|
|
$code = 403;
|
|
break;
|
|
|
|
case $e instanceof FileNotFoundException:
|
|
$code = 404;
|
|
break;
|
|
|
|
default:
|
|
$code = 500;
|
|
break;
|
|
}
|
|
|
|
return $code;
|
|
}
|
|
|
|
/**
|
|
* @return ItemPreviewer
|
|
*/
|
|
private function getItemPreviewer(): ItemPreviewer
|
|
{
|
|
/** @var ItemPreviewer $itemPreviewer */
|
|
$itemPreviewer = $this->getServiceLocator()->get(ItemPreviewer::class);
|
|
|
|
return $itemPreviewer;
|
|
}
|
|
|
|
/**
|
|
* Gets payload from the request
|
|
*
|
|
* @return array|mixed|object|null
|
|
*/
|
|
private function getPayload()
|
|
{
|
|
$jsonPayload = $this->getPsrRequest()->getParsedBody();
|
|
|
|
return json_decode($jsonPayload['itemResponse'], true);
|
|
}
|
|
}
|