* @author Gyula Szucs */ class RestQtiItem extends AbstractRestQti { use OntologyAwareTrait; const RESTITEM_PACKAGE_NAME = 'content'; /** * @inherit */ protected function getAcceptableMimeTypes() { return [ "application/json", "text/xml", "application/xml", "application/rdf+xml" , "application/zip", ]; } /** * Class items will be created in * * @return \core_kernel_classes_Class */ protected function getDestinationClass() { return $this->getClassFromRequest(new \core_kernel_classes_Class(TaoOntology::ITEM_CLASS_URI)); } /** * Only import method is available, so index return failure response */ public function index() { $this->returnFailure(new \common_exception_NotImplemented('This API does not support this call.')); } /** * Import file entry point by using $this->service * Check POST method & get valid uploaded file */ public function import() { try { if ($this->getRequestMethod() != Request::HTTP_POST) { throw new \common_exception_NotImplemented('Only post method is accepted to import Qti package.'); } // Get valid package parameter $package = $this->getUploadedPackage(); // Call service to import package \helpers_TimeOutHelper::setTimeOutLimit(\helpers_TimeOutHelper::LONG); $report = ImportService::singleton()->importQTIPACKFile( $package, $this->getDestinationClass(), true, true, true, $this->isMetadataGuardiansEnabled(), $this->isMetadataValidatorsEnabled(), $this->isItemMustExistEnabled(), $this->isItemMustBeOverwrittenEnabled() ); \helpers_TimeOutHelper::reset(); \tao_helpers_File::remove($package); if ($report->getType() !== \common_report_Report::TYPE_SUCCESS) { $message = __("An unexpected error occurred during the import of the IMS QTI Item Package. "); //get message of first error report if (!empty($report->getErrors())) { $message .= $report->getErrors()[0]->getMessage(); } $this->returnFailure(new \common_Exception($message)); } else { $itemIds = []; /** @var \common_report_Report $subReport */ foreach ($report as $subReport) { $itemIds[] = $subReport->getData()->getUri(); } $this->returnSuccess(['items' => $itemIds]); } } catch (ExtractException $e) { $this->returnFailure(new \common_Exception(__('The ZIP archive containing the IMS QTI Item cannot be extracted.'))); } catch (ParsingException $e) { $this->returnFailure(new \common_Exception(__('The ZIP archive does not contain an imsmanifest.xml file or is an invalid ZIP archive.'))); } catch (\Exception $e) { $this->returnFailure($e); } } /** * @inheritdoc */ protected function getTaskName() { return ImportQtiItem::class; } /** * Import item package through the task queue. */ public function importDeferred() { try { if ($this->getRequestMethod() != Request::HTTP_POST) { throw new \common_exception_NotImplemented('Only post method is accepted to import Qti package.'); } $task = ImportQtiItem::createTask( $this->getUploadedPackage(), $this->getDestinationClass(), $this->getServiceLocator(), $this->isMetadataGuardiansEnabled(), $this->isMetadataValidatorsEnabled(), $this->isItemMustExistEnabled(), $this->isItemMustBeOverwrittenEnabled() ); $result = [ 'reference_id' => $task->getId() ]; /** @var TaskLogInterface $taskLog */ $taskLog = $this->getServiceManager()->get(TaskLogInterface::SERVICE_ID); if ($report = $taskLog->getReport($task->getId())) { $result['report'] = $report->toArray(); } return $this->returnSuccess($result); } catch (\Exception $e) { return $this->returnFailure($e); } } /** * Add extra values to the JSON returned. * * @param EntityInterface $taskLogEntity * @return array */ protected function addExtraReturnData(EntityInterface $taskLogEntity) { $data = []; if ($taskLogEntity->getReport()) { $plainReport = $this->getPlainReport($taskLogEntity->getReport()); //the third report is report of import test $itemsReport = array_slice($plainReport, 2); foreach ($itemsReport as $itemReport) { if (isset($itemReport->getData()['uriResource'])) { $data['itemIds'][] = $itemReport->getData()['uriResource']; } } } return $data; } /** * Return a valid uploaded file * * @return string * @throws \common_Exception * @throws \common_exception_Error * @throws \common_exception_MissingParameter * @throws \common_exception_BadRequest * @throws \oat\tao\helpers\FileUploadException */ protected function getUploadedPackage() { if (!$this->hasRequestParameter(self::RESTITEM_PACKAGE_NAME)) { throw new \common_exception_MissingParameter(self::RESTITEM_PACKAGE_NAME, __CLASS__); } $file = \tao_helpers_Http::getUploadedFile(self::RESTITEM_PACKAGE_NAME); if (!in_array($file['type'], self::$accepted_types)) { throw new \common_exception_BadRequest('Uploaded file has to be a valid archive.'); } $pathinfo = pathinfo($file['tmp_name']); $destination = $pathinfo['dirname'] . DIRECTORY_SEPARATOR . $file['name']; \tao_helpers_File::move($file['tmp_name'], $destination); return $destination; } /** * Create an empty item */ public function createQtiItem() { try { // Check if it's post method if ($this->getRequestMethod() != Request::HTTP_POST) { throw new \common_exception_NotImplemented('Only post method is accepted to create empty item.'); } $label = $this->hasRequestParameter('label') ? $this->getRequestParameter('label') : ''; // Call service to import package $item = $this->getDestinationClass()->createInstance($label); //set the QTI type $itemService = \taoItems_models_classes_ItemsService::singleton(); $itemService->setItemModel($item, $this->getResource(ItemModel::MODEL_URI)); $this->returnSuccess($item->getUri()); } catch (\Exception $e) { $this->returnFailure($e); } } /** * render an item as a Qti zip package * @author christophe GARCIA */ public function export() { try { if ($this->getRequestMethod() != Request::HTTP_GET) { throw new \common_exception_NotImplemented('Only GET method is accepted to export QIT Item.'); } if (!$this->hasRequestParameter('id')) { $this->returnFailure(new \common_exception_MissingParameter('required parameter `id` is missing')); } $id = $this->getRequestParameter('id'); $item = new \core_kernel_classes_Resource($id); $itemService = \taoItems_models_classes_ItemsService::singleton(); if ($itemService->hasItemModel($item, [ItemModel::MODEL_URI])) { $path = \tao_helpers_Export::getExportFile(); $tmpZip = new \ZipArchive(); $tmpZip->open($path, \ZipArchive::CREATE); $exporter = new QTIPackedItemExporter($item, $tmpZip); $exporter->export(['apip' => false]); $exporter->getZip()->close(); header('Content-Type: application/zip'); \tao_helpers_Http::returnFile($path, false); return; } else { $this->returnFailure(new \common_exception_NotFound('item can\'t be found')); } } catch (\Exception $e) { $this->returnFailure($e); } } /** * Create an Item Class * * Label parameter is mandatory * If parent class parameter is an uri of valid test class, new class will be created under it * If not parent class parameter is provided, class will be created under root class * Comment parameter is not mandatory, used to describe new created class * * @return \core_kernel_classes_Class */ public function createClass() { try { $class = $this->createSubClass(new \core_kernel_classes_Class(TaoOntology::ITEM_CLASS_URI)); $result = [ 'message' => __('Class successfully created.'), 'class-uri' => $class->getUri(), ]; $this->returnSuccess($result); } catch (\common_exception_ClassAlreadyExists $e) { $result = [ 'message' => $e->getMessage(), 'class-uri' => $e->getClass()->getUri(), ]; $this->returnSuccess($result); } catch (\Exception $e) { $this->returnFailure($e); } } }