From 13ec1f9b06b5d332a36eac8289608eed47428b7f Mon Sep 17 00:00:00 2001 From: Yannick Warnier Date: Tue, 25 Jun 2024 17:21:32 +0200 Subject: [PATCH] Maintenance: CommonCartridge: Fix issue uploading referenced 'webcontent' files to the documents tool ('commoncartridge' folder) - refs BT#21709 --- main/common_cartridge/import/Cc1p3Convert.php | 10 ++- .../import/src/base/CcBase.php | 68 +++++++++++++------ .../import/src/converter/Cc13Quiz.php | 6 +- .../import/src/converter/Cc13Resource.php | 50 +++++++++----- 4 files changed, 91 insertions(+), 43 deletions(-) diff --git a/main/common_cartridge/import/Cc1p3Convert.php b/main/common_cartridge/import/Cc1p3Convert.php index 5828d086f0..1f900bc678 100644 --- a/main/common_cartridge/import/Cc1p3Convert.php +++ b/main/common_cartridge/import/Cc1p3Convert.php @@ -39,9 +39,15 @@ class Cc1p3Convert extends CcBase */ public function generateImportData(): void { + $countInstances = 0; $xpath = static::newxPath(static::$manifest, static::$namespaces); + // Scan for detached resources of type 'webcontent' + $resources = $xpath->query('/imscc:manifest/imscc:resources/imscc:resource[@type="'.static::CC_TYPE_WEBCONTENT.'"]'); + $this->createInstances($resources, 0, $countInstances); + + // Scan for organization items or resources that are tests (question banks) $items = $xpath->query('/imscc:manifest/imscc:organizations/imscc:organization/imscc:item | /imscc:manifest/imscc:resources/imscc:resource[@type="'.static::CC_TYPE_QUESTION_BANK.'"]'); - $this->createInstances($items); + $this->createInstances($items, 0,$countInstances); $resources = new Cc13Resource(); $forums = new Cc13Forum(); @@ -66,7 +72,7 @@ class Cc1p3Convert extends CcBase $groupId, null, $documentPath, - '/cc1p3', + '/commoncartridge', 'Common Cartridge folder', 0 ); diff --git a/main/common_cartridge/import/src/base/CcBase.php b/main/common_cartridge/import/src/base/CcBase.php index e93aa2499d..852787ccf7 100644 --- a/main/common_cartridge/import/src/base/CcBase.php +++ b/main/common_cartridge/import/src/base/CcBase.php @@ -66,7 +66,12 @@ class CcBase return static::$resourcens; } - public static function getManifest($folder) + /** + * Find the imsmanifest.xml file inside the given folder and return its path + * @param string $folder Full path name of the folder in which we expect to find imsmanifest.xml + * @return false|string + */ + public static function getManifest(string $folder) { if (!is_dir($folder)) { return false; @@ -156,6 +161,19 @@ class CcBase } } + public function getItemHref($identifier) + { + $xpath = static::newxPath(static::$manifest, static::$namespaces); + + $nodes = $xpath->query('/imscc:manifest/imscc:resources/imscc:resource[@identifier="'.$identifier.'"]/imscc:file/@href'); + + if ($nodes && !empty($nodes->item(0)->nodeValue)) { + return $nodes->item(0)->nodeValue; + } else { + return ''; + } + } + public static function newxPath(DOMDocument $manifest, $namespaces = '') { $xpath = new DOMXPath($manifest); @@ -257,13 +275,12 @@ class CcBase foreach ($items as $item) { $array_index++; - if ($item->nodeName == "item") { - $identifierref = ''; + $title = $path = $tool_type = $identifierref = ''; + if ($item->nodeName == 'item') { if ($item->hasAttribute('identifierref')) { $identifierref = $item->getAttribute('identifierref'); } - $title = ''; $titles = $xpath->query('imscc:title', $item); if ($titles->length > 0) { $title = $titles->item(0)->nodeValue; @@ -275,34 +292,43 @@ class CcBase if (empty($identifierref) && empty($title)) { $tool_type = TYPE_UNKNOWN; } - } elseif ($item->nodeName == "resource") { + } elseif ($item->nodeName == 'resource') { $identifierref = $xpath->query('@identifier', $item); $identifierref = !empty($identifierref->item(0)->nodeValue) ? $identifierref->item(0)->nodeValue : ''; $ccType = $this->getItemCcType($identifierref); $tool_type = $this->convertToToolType($ccType); - - $title = 'Quiz Bank '.($this->countInstances($tool_type) + 1); + if (self::CC_TYPE_WEBCONTENT == $ccType) { + $path = $this->getItemHref($identifierref); + $title = basename($path); + } else { // A resource but not a file... we assume it's a quiz bank and its assigned identifier is irrelevant to its name + $title = 'Quiz Bank '.($this->countInstances($tool_type) + 1); + } } if ($level == ROOT_DEEP) { $index_root = $array_index; } - static::$instances['index'][$array_index]['common_cartridge_type'] = $ccType; - static::$instances['index'][$array_index]['tool_type'] = $tool_type; - static::$instances['index'][$array_index]['title'] = $title ? $title : ''; - static::$instances['index'][$array_index]['root_parent'] = $index_root; - static::$instances['index'][$array_index]['index'] = $array_index; - static::$instances['index'][$array_index]['deep'] = $level; - static::$instances['index'][$array_index]['instance'] = $this->countInstances($tool_type); - static::$instances['index'][$array_index]['resource_identifier'] = $identifierref; - - static::$instances['instances'][$tool_type][] = ['title' => $title, - 'instance' => static::$instances['index'][$array_index]['instance'], - 'common_cartridge_type' => $ccType, - 'resource_identifier' => $identifierref, - 'deep' => $level, ]; + static::$instances['index'][$array_index] = [ + 'common_cartridge_type' => $ccType, + 'tool_type' => $tool_type, + 'title' => $title ? $title : '', + 'root_parent' => $index_root, + 'index' => $array_index, + 'deep' => $level, + 'instance' => $this->countInstances($tool_type), + 'resource_identifier' => $identifierref, + ]; + + static::$instances['instances'][$tool_type][] = [ + 'title' => $title, + 'instance' => static::$instances['index'][$array_index]['instance'], + 'common_cartridge_type' => $ccType, + 'resource_identifier' => $identifierref, + 'deep' => $level, + 'src' => $path, + ]; $more_items = $xpath->query('imscc:item', $item); diff --git a/main/common_cartridge/import/src/converter/Cc13Quiz.php b/main/common_cartridge/import/src/converter/Cc13Quiz.php index da1e5f26e4..30d56a021a 100644 --- a/main/common_cartridge/import/src/converter/Cc13Quiz.php +++ b/main/common_cartridge/import/src/converter/Cc13Quiz.php @@ -31,6 +31,8 @@ class Cc13Quiz extends Cc13Entities { $token = '/\$(?:IMS|1EdTech)[-_]CC[-_]FILEBASE\$/'; $courseInfo = api_get_course_info(); + // Replace by the path in documents in which we place all relevant CC files + $replacementPath = '/courses/'.$courseInfo['directory'].'/document/commoncartridge/'; $exercise = new Exercise($courseInfo['real_id']); $title = Exercise::format_title_variable($quiz['title']); $exercise->updateTitle($title); @@ -66,9 +68,9 @@ class Cc13Quiz extends Cc13Entities $questionInstance->updateTitle(substr(Security::remove_XSS(strip_tags_blacklist($question['title'], ['br', 'p'])), 0, 20)); $questionText = Security::remove_XSS(strip_tags_blacklist($question['title'], ['br', 'p'])); // Replace the path from $1EdTech-CC-FILEBASE$ to a correct chamilo path - $questionText = preg_replace($token, '/courses/'.$courseInfo['path'].'/document', $questionText); - + $questionText = preg_replace($token, $replacementPath, $questionText); $questionInstance->updateDescription($questionText); + $questionInstance->updateLevel(1); $questionInstance->updateCategory(0); diff --git a/main/common_cartridge/import/src/converter/Cc13Resource.php b/main/common_cartridge/import/src/converter/Cc13Resource.php index b4082ac7cb..440beb5d8d 100644 --- a/main/common_cartridge/import/src/converter/Cc13Resource.php +++ b/main/common_cartridge/import/src/converter/Cc13Resource.php @@ -32,6 +32,9 @@ class Cc13Resource extends Cc13Entities public function storeDocuments($documents, $path) { $courseInfo = api_get_course_info(); + $sessionId = api_get_session_id(); + $groupId = api_get_group_id(); + $documentPath = api_get_path(SYS_COURSE_PATH).$courseInfo['directory'].'/document'; foreach ($documents as $document) { if ($document[2] == 'file') { @@ -47,9 +50,22 @@ class Cc13Resource extends Cc13Entities $_POST['language'] = $courseInfo['language']; $_POST['cc_import'] = true; + $destDir = dirname($document[4]); + // Create the subdirectory if necessary + create_unexisting_directory( + $courseInfo, + api_get_user_id(), + $sessionId, + $groupId, + null, + $documentPath, + '/commoncartridge/'.$destDir, + $destDir, + 1 + ); DocumentManager::upload_document( $files, - '/cc1p3', + '/commoncartridge/'.$destDir, $document[1], '', null, @@ -80,12 +96,8 @@ class Cc13Resource extends Cc13Entities if (empty($resource)) { unset($resource); - $resource = $xpath->query('/imscc:manifest/imscc:resources/imscc:resource[@identifier="'.$instance['resource_identifier'].'"]/imscc:file/@href'); - if ($resource->length > 0) { - $resource = !empty($resource->item(0)->nodeValue) ? $resource->item(0)->nodeValue : ''; - } else { - $resource = ''; - } + // src has been set in CcBase::createInstances() based on the contents of + $resource = $instance['src']; } if (!empty($resource)) { $link = $resource; @@ -93,7 +105,8 @@ class Cc13Resource extends Cc13Entities } if ($instance['common_cartridge_type'] == Cc1p3Convert::CC_TYPE_WEBLINK) { - $external_resource = $xpath->query('/imscc:manifest/imscc:resources/imscc:resource[@identifier="'.$instance['resource_identifier'].'"]/imscc:file/@href')->item(0)->nodeValue; + // src has been set in CcBase::createInstances() based on the contents of + $external_resource = $instance['src']; if ($external_resource) { $resource = $this->loadXmlResource(Cc1p3Convert::$pathToManifestFolder.DIRECTORY_SEPARATOR.$external_resource); @@ -122,12 +135,12 @@ class Cc13Resource extends Cc13Entities $mod_options = 'objectframe'; $mod_reference = $link; $mod_alltext = ''; - //detected if we are dealing with html file + // detect if we are dealing with html file if (!empty($link) && ($instance['common_cartridge_type'] == Cc1p3Convert::CC_TYPE_WEBCONTENT)) { $ext = strtolower(pathinfo($link, PATHINFO_EXTENSION)); if (in_array($ext, ['html', 'htm', 'xhtml'])) { $mod_type = 'html'; - //extract the content of the file + //extract the content of the file and treat it $rootpath = realpath(Cc1p3Convert::$pathToManifestFolder); $htmlpath = realpath($rootpath.DIRECTORY_SEPARATOR.$link); $dirpath = dirname($htmlpath); @@ -163,7 +176,7 @@ class Cc13Resource extends Cc13Entities $rtp = realpath($rpath); if (($rtp !== false) && is_file($rtp)) { //file is there - we are in business - $strip = str_replace("\\", "/", str_ireplace($rootpath, '', $rtp)); + $strip = str_replace("\\", "/", str_ireplace($rootpath, '/', $rtp)); //$encoded_file = '$@FILEPHP@$'.str_replace('/', '$@SLASH@$', $strip); $encoded_file = $strip; $searches[] = $resrc->nodeValue; @@ -180,13 +193,14 @@ class Cc13Resource extends Cc13Entities } } - $values = [$instance['instance'], - self::safexml($instance['title']), - $mod_type, - $mod_alltext, - $mod_reference, - $mod_options, - ]; + $values = [ + $instance['instance'], + self::safexml($instance['title']), + $mod_type, + $mod_alltext, + $mod_reference, // src or href + $mod_options, + ]; return $values; }