Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/aut 3590/add metadata check on import #2454

Merged
merged 37 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
59a426f
feat: export test will inject properties description in root metadata…
bartlomiejmarszal Apr 9, 2024
393bdbb
feat: fix phpcs issues
bartlomiejmarszal Apr 9, 2024
d0b57ba
feat: fix phpcs issues
bartlomiejmarszal Apr 9, 2024
f946de0
feat: add Feature Flag
bartlomiejmarszal Apr 9, 2024
9dac940
feat: extract checksum to service, remove interface
bartlomiejmarszal Apr 10, 2024
129d4bc
feat: phpcs fix
bartlomiejmarszal Apr 10, 2024
5b0794d
feat: add import metametadata
Karol-Stelmaczonek Apr 10, 2024
8d0bb00
chore: add debug for checksum
Karol-Stelmaczonek Apr 11, 2024
aacccee
feat: add sorting and to lower for checksum
Karol-Stelmaczonek Apr 11, 2024
232ac35
Merge branch 'feat/AUT-3589/add-properties-in-root-ims-manifest' into…
Karol-Stelmaczonek Apr 11, 2024
926c553
feat: additional fixes for checksum
Karol-Stelmaczonek Apr 11, 2024
edccf52
Merge branch 'feat/AUT-3589/add-properties-in-root-ims-manifest' into…
Karol-Stelmaczonek Apr 11, 2024
4d88aed
chore: refactor & rename
Karol-Stelmaczonek Apr 12, 2024
95b2336
chore: phpcbf fixes
Karol-Stelmaczonek Apr 15, 2024
0bc78b6
chore: phpcbf fixes
Karol-Stelmaczonek Apr 15, 2024
3e30b13
feat: add metadata import for items and tests
bartlomiejmarszal Apr 16, 2024
2ac9845
feat: Merge branch 'feat/aut-3590/add-metadata-check-on-import' into …
bartlomiejmarszal Apr 16, 2024
bea3f55
feat: Remove MetaMetadataValidator. Move business logic into matcher
bartlomiejmarszal Apr 18, 2024
aa3aa6b
feat: phpsbf fix
bartlomiejmarszal Apr 18, 2024
f1f6616
feat: move ChecksumGenerator to taoQtiItems
bartlomiejmarszal Apr 18, 2024
52cb224
chore: remove unused code
Karol-Stelmaczonek Apr 18, 2024
d0e78fc
feat: GenericLomOntologyExtractorTest
bartlomiejmarszal Apr 18, 2024
26007e9
Merge remote-tracking branch 'origin/feat/aut-3590/add-metadata-check…
Karol-Stelmaczonek Apr 18, 2024
818b02f
Merge remote-tracking branch 'origin/feat/aut-3590/add-metadata-check…
Karol-Stelmaczonek Apr 18, 2024
4cf0215
feat: temp composer fix
bartlomiejmarszal Apr 18, 2024
81c31d4
Merge branch 'feat/aut-3590/add-metadata-check-on-import' of https://…
bartlomiejmarszal Apr 18, 2024
959026a
chore: phpcbf fixes
Karol-Stelmaczonek Apr 18, 2024
394deab
Merge remote-tracking branch 'origin/feat/aut-3590/add-metadata-check…
Karol-Stelmaczonek Apr 18, 2024
9a6a205
feat: add form checkbox in import test form
bartlomiejmarszal May 2, 2024
a480dd7
Merge branch 'feat/aut-3590/add-metadata-check-on-import' of https://…
bartlomiejmarszal May 2, 2024
b516f30
feat: phpcbf automatic fix
bartlomiejmarszal May 2, 2024
361b66d
feat: When importing a test, item metadata values are imported
bartlomiejmarszal May 2, 2024
ad82c29
feat: Export using this same FF
bartlomiejmarszal May 3, 2024
16ee3c9
fix: define default array
bartlomiejmarszal May 6, 2024
cd9a9a1
fix: Connect test import form
bartlomiejmarszal May 7, 2024
431778f
fix: Decorate form with metadata. Overload getTaskParams
bartlomiejmarszal May 7, 2024
effe9f7
fix: oat-sa/extension-tao-itemqti - 30.10.0 dependency
bartlomiejmarszal May 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"oat-sa/generis" : ">=15.22",
"oat-sa/tao-core": ">=54.0.0",
"oat-sa/extension-tao-item" : ">=12.1.0",
"oat-sa/extension-tao-itemqti" : ">=30.0.0",
"oat-sa/extension-tao-itemqti" : "dev-feat/aut-3590-add-metadata-check-on-import",
"oat-sa/extension-tao-test" : ">=16.0.0",
"oat-sa/extension-tao-delivery" : ">=15.0.0",
"oat-sa/extension-tao-outcome" : ">=13.0.0",
Expand Down
4 changes: 3 additions & 1 deletion manifest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

use oat\tao\model\user\TaoRoles;
use oat\taoQtiTest\model\Container\TestQtiServiceProvider;
use oat\taoQtiTest\models\classes\metadata\MetadataServiceProvider;
// phpcs:disable Generic.Files.LineLength
use oat\taoQtiTest\models\classes\render\CustomInteraction\ServiceProvider\CustomInteractionPostProcessingServiceProvider;
// phpcs:enable Generic.Files.LineLength
Expand Down Expand Up @@ -182,6 +183,7 @@
CustomInteractionPostProcessingServiceProvider::class,
ItemsReferencesServiceProvider::class,
TestQtiServiceProvider::class,
TestSessionStateServiceProvider::class
TestSessionStateServiceProvider::class,
MetadataServiceProvider::class
],
];
32 changes: 30 additions & 2 deletions models/classes/class.QtiTestService.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@
use oat\taoItems\model\Command\DeleteItemCommand;
use oat\taoQtiItem\model\qti\ImportService;
use oat\taoQtiItem\model\qti\metadata\importer\MetadataImporter;
use oat\taoQtiItem\model\qti\metadata\imsManifest\MetaMetadataExtractor;
use oat\taoQtiItem\model\qti\metadata\importer\MetaMetadataImportMapper;
use oat\taoQtiItem\model\qti\metadata\importer\PropertyDoesNotExistException;
use oat\taoQtiItem\model\qti\metadata\MetadataGuardianResource;
use oat\taoQtiItem\model\qti\metadata\MetadataService;
use oat\taoQtiItem\model\qti\metadata\ontology\MappedMetadataInjector;
use oat\taoQtiItem\model\qti\Resource;
use oat\taoQtiItem\model\qti\Service;
use oat\taoQtiTest\models\cat\AdaptiveSectionInjectionException;
Expand All @@ -50,6 +54,7 @@
use qtism\data\storage\xml\XmlDocument;
use qtism\data\storage\xml\XmlStorageException;
use taoTests_models_classes_TestsService as TestService;
use oat\oatbox\reporting\Report;

/**
* the QTI TestModel service.
Expand Down Expand Up @@ -570,6 +575,7 @@ protected function importTest(
$domManifest->load($folder . 'imsmanifest.xml');

$metadataValues = $this->getMetadataImporter()->extract($domManifest);
$metaMetadataValues = $this->getMetaMetadataExtractor()->extract($domManifest);

// Note: without this fix, metadata guardians do not work.
$this->getMetadataImporter()->setMetadataValues($metadataValues);
Expand All @@ -583,6 +589,7 @@ protected function importTest(
$reportCtx->overwrittenItems = [];
$reportCtx->itemQtiResources = [];
$reportCtx->testMetadata = $metadataValues[$qtiTestResourceIdentifier] ?? [];
$reportCtx->metaMetadata = $metaMetadataValues;
$reportCtx->createdClasses = [];

// 'uriResource' key is needed by javascript in tao/views/templates/form/import.tpl
Expand Down Expand Up @@ -625,6 +632,8 @@ protected function importTest(
}

$targetItemClass = $itemParentClass->createSubClass(self::IN_PROGRESS_LABEL);
$mappedProperties = $this->getMetaMetadataImporter()
->mapMetaMetadataToProperties($metaMetadataValues, $targetItemClass, $testClass);

// add real label without saving (to not pass it separately to item importer)
$targetItemClass->label = $testLabel;
Expand Down Expand Up @@ -679,7 +688,6 @@ protected function importTest(
);
}
}

// Skip if $qtiFile already imported (multiple assessmentItemRef "hrefing" the same
// file).
if (array_key_exists($qtiFile, $alreadyImportedTestItemFiles) === false) {
Expand All @@ -697,7 +705,8 @@ protected function importTest(
$this->useMetadataValidators,
$this->itemMustExist,
$this->itemMustBeOverwritten,
$reportCtx->overwrittenItems
$reportCtx->overwrittenItems,
$mappedProperties['itemProperties']
);

$reportCtx->createdClasses = array_merge(
Expand Down Expand Up @@ -780,6 +789,11 @@ protected function importTest(
// 4. Import metadata for the resource (use same mechanics as item resources).
// Metadata will be set as property values.
$this->getMetadataImporter()->inject($qtiTestResource->getIdentifier(), $testResource);
$this->getServiceManager()->getContainer()->get(MappedMetadataInjector::class)->inject(
$mappedProperties['testProperties'],
$metadataValues[$qtiTestResourceIdentifier],
$testResource
);

// 5. if $targetClass does not contain any instances
// (because everything resolved by class lookups),
Expand Down Expand Up @@ -833,6 +847,9 @@ protected function importTest(

$msg = __("Error found in the IMS QTI Test:\n%s", $finalErrorString);
$report->add(common_report_Report::createFailure($msg));
} catch (PropertyDoesNotExistException $e) {
$reportCtx->itemClass = $targetItemClass;
$report->add(Report::createError($e->getMessage()));
} catch (CatEngineNotFoundException $e) {
$report->add(
new common_report_Report(
Expand Down Expand Up @@ -1411,6 +1428,12 @@ protected function getMetadataImporter()
return $this->metadataImporter;
}

private function getMetaMetadataExtractor(): MetaMetadataExtractor
{
return $this->getPsrContainer()->get(MetaMetadataExtractor::class);
return $this->getServiceManager()->getContainer()->get(MetaMetadataExtractor::class);
}

private function getSecureResourceService(): SecureResourceServiceInterface
{
return $this->getServiceLocator()->get(SecureResourceServiceInterface::SERVICE_ID);
Expand Down Expand Up @@ -1488,4 +1511,9 @@ private function getPsrContainer(): ContainerInterface
{
return $this->getServiceLocator()->getContainer();
}

private function getMetaMetadataImporter(): MetaMetadataImportMapper
{
return $this->getServiceManager()->getContainer()->get(MetaMetadataImportMapper::class);
}
}
21 changes: 21 additions & 0 deletions models/classes/export/AbstractQtiTestExporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
use DOMXPath;
use oat\oatbox\reporting\Report;
use oat\oatbox\reporting\ReportInterface;
use oat\tao\model\featureFlag\FeatureFlagChecker;
use oat\taoQtiTest\models\classes\metadata\GenericLomOntologyExtractor;
use qtism\data\storage\xml\marshalling\MarshallingException;
use qtism\data\storage\xml\XmlDocument;
use oat\oatbox\filesystem\Directory;
Expand All @@ -48,6 +50,8 @@

abstract class AbstractQtiTestExporter extends ItemExporter implements QtiTestExporterInterface
{
public const FEATURE_FLAG_LOM_ONTOLOGY_EXTRACTION = 'FEATURE_FLAG_LOM_ONTOLOGY_EXTRACTION';

/** The QTISM XmlDocument representing the Test to be exported. */
private XmlDocument $testDocument;

Expand Down Expand Up @@ -174,6 +178,13 @@ public function export(array $options = []): Report
// 3. Export test metadata to manifest
$this->getMetadataExporter()->export($this->getItem(), $this->getManifest());

if ($this->getFeatureFlagChecker()->isEnabled(self::FEATURE_FLAG_LOM_ONTOLOGY_EXTRACTION)) {
$this->genericLomOntologyExtractor()->extract(
array_merge([$this->getItem()], $this->getItems()),
$this->getManifest()
);
}

// 4. Persist manifest in archive.
$this->getZip()->addFromString('imsmanifest.xml', $this->getManifest()->saveXML());

Expand Down Expand Up @@ -350,4 +361,14 @@ protected function getServiceManager(): ServiceManager
{
return ServiceManager::getServiceManager();
}

private function genericLomOntologyExtractor(): GenericLomOntologyExtractor
{
return $this->getServiceManager()->getContainer()->get(GenericLomOntologyExtractor::class);
}

private function getFeatureFlagChecker(): FeatureFlagChecker
{
return $this->getServiceManager()->getContainer()->get(FeatureFlagChecker::class);
}
}
86 changes: 86 additions & 0 deletions models/classes/metadata/GenericLomOntologyExtractor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?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) 2024 (original work) Open Assessment Technologies SA;
*/

declare(strict_types=1);

namespace oat\taoQtiTest\models\classes\metadata;

use core_kernel_classes_Resource as Resource;
use core_kernel_classes_Triple as Triple;
use DOMDocument;
use oat\generis\model\data\Ontology;
use oat\taoQtiItem\model\qti\metadata\MetadataExtractionException;
use oat\taoQtiTest\models\classes\metadata\metaMetadata\PropertyMapper;

class GenericLomOntologyExtractor
{
private Ontology $ontology;
private PropertyMapper $propertyMapper;
private MetadataLomService $metadataLomService;

public function __construct(
Ontology $ontology,
PropertyMapper $propertyMapper,
MetadataLomService $metadataLomService
) {
$this->ontology = $ontology;
$this->propertyMapper = $propertyMapper;
$this->metadataLomService = $metadataLomService;
}

/**
* @param Resource[] $resourceCollection
* @throws MetadataExtractionException
*/
public function extract(array $resourceCollection, DOMDocument $manifest): void
{
$properties = [];

foreach ($resourceCollection as $resource) {
if (!$resource instanceof Resource) {
throw new MetadataExtractionException(
__('The given target is not an instance of core_kernel_classes_Resource')
);
}

foreach ($resource->getRdfTriples() as $triple) {
if ($this->mappingRequired($properties, $triple)) {
$properties[] = $this->propertyMapper
->getMetadataProperties(
$this->ontology->getProperty($triple->predicate)
);
}
}
}

$this->metadataLomService->addPropertiesToMetadataBlock($properties, $manifest);
}

/**
* Mapping action only applies for confirmed properties that are not already mapped
*/
private function mappingRequired(array $properties, Triple $triple): bool
{
return $this->ontology->getProperty($triple->predicate)->isProperty() &&
array_filter($properties, function ($property) use ($triple) {
return $property['uri'] === $triple->predicate;
}) === [];
}
}
57 changes: 57 additions & 0 deletions models/classes/metadata/MetadataLomService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?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) 2024 (original work) Open Assessment Technologies SA;
*/

declare(strict_types=1);

namespace oat\taoQtiTest\models\classes\metadata;

use DOMDocument;
use DOMNodeList;

class MetadataLomService
{
public function addPropertiesToMetadataBlock(array $properties, DOMDocument $manifest): void
{
/** @var DOMNodeList $metadataBlock */
$metadataBlock = $manifest->getElementsByTagName('metadata');

if ($metadataBlock === null) {
$metadataBlock = $manifest->createElement('metadata');
$manifest->documentElement->appendChild($metadataBlock);
}

$metadataBlock->item(0)
->appendChild($manifest->createElement('imsmd:lom'))
->appendChild($manifest->createElement('imsmd:metaMetadata'))
->appendChild($manifest->createElement('extension'))
->appendChild($manifest->createElement('customProperties'));

foreach ($properties as $property) {
$propertyNode = $manifest->createElement('property');
foreach ($property as $key => $value) {
$propertyNode->appendChild($manifest->createElement($key, $value));
}
$metadataBlock->item(0)
->getElementsByTagName('customProperties')
->item(0)
->appendChild($propertyNode);
}
}
}
62 changes: 62 additions & 0 deletions models/classes/metadata/MetadataServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?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) 2024 (original work) Open Assessment Technologies SA;
*/

declare(strict_types=1);

namespace oat\taoQtiTest\models\classes\metadata;

use oat\generis\model\data\Ontology;
use oat\generis\model\DependencyInjection\ContainerServiceProviderInterface;
use oat\generis\model\GenerisRdf;
use oat\taoQtiItem\model\import\ChecksumGenerator;
use oat\taoQtiTest\models\classes\metadata\metaMetadata\PropertyMapper;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

use function Symfony\Component\DependencyInjection\Loader\Configurator\service;

class MetadataServiceProvider implements ContainerServiceProviderInterface
{
public function __invoke(ContainerConfigurator $configurator): void
{
$services = $configurator->services();

$services->set(MetadataLomService::class, MetadataLomService::class);

$services->set(PropertyMapper::class, PropertyMapper::class)
->args([
service(ChecksumGenerator::class),
[
'label' => RDFS_LABEL,
'domain' => RDFS_DOMAIN,
'alias' => GenerisRdf::PROPERTY_ALIAS,
'multiple' => GenerisRdf::PROPERTY_MULTIPLE
]
]);

$services
->set(GenericLomOntologyExtractor::class, GenericLomOntologyExtractor::class)
->public()
->args([
service(Ontology::SERVICE_ID),
service(PropertyMapper::class),
service(MetadataLomService::class)
]);
}
}
Loading
Loading