Skip to content

Commit

Permalink
Merge branch 'release-48.18.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions committed Dec 20, 2024
2 parents 8218928 + 23807d9 commit 82f46b7
Show file tree
Hide file tree
Showing 11 changed files with 649 additions and 7 deletions.
2 changes: 2 additions & 0 deletions actions/class.Runner.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
use oat\taoQtiTest\model\Service\TimeoutService;
use oat\taoQtiTest\model\Service\ToolsStateAwareInterface;
use oat\taoQtiTest\models\cat\CatEngineNotFoundException;
use oat\taoQtiTest\models\classes\runner\QtiRunnerInvalidResponsesException;
use oat\taoQtiTest\models\container\QtiTestDeliveryContainer;
use oat\taoQtiTest\models\runner\communicator\CommunicationService;
use oat\taoQtiTest\models\runner\communicator\QtiCommunicationService;
Expand Down Expand Up @@ -274,6 +275,7 @@ protected function getStatusCodeFromException(Exception $exception): int
case QtiRunnerEmptyResponsesException::class:
case QtiRunnerClosedException::class:
case QtiRunnerPausedException::class:
case QtiRunnerInvalidResponsesException::class:
return 200;

case common_exception_NotImplemented::class:
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"ext-zip": "*",
"oat-sa/lib-test-cat": "2.4.0",
"oat-sa/oatbox-extension-installer": "~1.1||dev-master",
"qtism/qtism": ">=0.28.3",
"qtism/qtism": ">=0.28.7",
"oat-sa/generis": ">=16.0.0",
"oat-sa/tao-core": ">=54.27.0",
"oat-sa/extension-tao-item": ">=12.4.0",
Expand Down
21 changes: 20 additions & 1 deletion model/Container/TestQtiServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@
use oat\taoQtiTest\model\Domain\Model\QtiTestRepositoryInterface;
use oat\taoQtiTest\model\Domain\Model\ToolsStateRepositoryInterface;
use oat\taoQtiTest\model\Infrastructure\QtiItemResponseRepository;
use oat\taoQtiTest\model\Infrastructure\QtiItemResponseValidator;
use oat\taoQtiTest\model\Infrastructure\QtiToolsStateRepository;
use oat\taoQtiTest\model\Infrastructure\QtiTestRepository;
use oat\taoQtiTest\model\Service\ConcurringSessionService;
use oat\taoQtiTest\model\Service\ExitTestService;
use oat\taoQtiTest\model\Service\ListItemsService;
use oat\taoQtiTest\model\Service\MoveService;
use oat\taoQtiTest\model\Service\PauseService;
use oat\taoQtiTest\model\Service\PluginManagerService;
use oat\taoQtiTest\model\Service\SkipService;
use oat\taoQtiTest\model\Service\StoreTraceVariablesService;
use oat\taoQtiTest\model\Service\TimeoutService;
Expand All @@ -49,6 +51,7 @@
use oat\taoQtiTest\models\TestModelService;
use oat\taoQtiTest\models\TestSessionService;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use common_ext_ExtensionsManager as ExtensionsManager;

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

Expand All @@ -63,7 +66,9 @@ public function __invoke(ContainerConfigurator $configurator): void
->public()
->args(
[
service(QtiRunnerService::SERVICE_ID)
service(QtiRunnerService::SERVICE_ID),
service(FeatureFlagChecker::class),
service(QtiItemResponseValidator::class),
]
);

Expand Down Expand Up @@ -176,5 +181,19 @@ public function __invoke(ContainerConfigurator $configurator): void
service(TimerAdjustmentServiceInterface::SERVICE_ID),
]
);

$services
->set(QtiItemResponseValidator::class, QtiItemResponseValidator::class)
->public();

$services
->set(PluginManagerService::class, PluginManagerService::class)
->args(
[
service(Ontology::SERVICE_ID),
service(ExtensionsManager::SERVICE_ID),
]
)
->public();
}
}
27 changes: 24 additions & 3 deletions model/Infrastructure/QtiItemResponseRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,32 @@

namespace oat\taoQtiTest\model\Infrastructure;

use oat\tao\model\featureFlag\FeatureFlagChecker;
use oat\taoQtiTest\model\Domain\Model\ItemResponse;
use oat\taoQtiTest\model\Domain\Model\ItemResponseRepositoryInterface;
use oat\taoQtiTest\models\classes\runner\QtiRunnerInvalidResponsesException;
use oat\taoQtiTest\models\runner\QtiRunnerEmptyResponsesException;
use oat\taoQtiTest\models\runner\QtiRunnerItemResponseException;
use oat\taoQtiTest\models\runner\QtiRunnerService;
use oat\taoQtiTest\models\runner\RunnerServiceContext;
use qtism\runtime\tests\AssessmentItemSessionException;
use taoQtiTest_helpers_TestRunnerUtils as TestRunnerUtils;

class QtiItemResponseRepository implements ItemResponseRepositoryInterface
{
/** @var QtiRunnerService */
private $runnerService;

public function __construct(QtiRunnerService $runnerService)
{
private FeatureFlagChecker $featureFlagChecker;
private QtiItemResponseValidator $itemResponseValidator;

public function __construct(
QtiRunnerService $runnerService,
FeatureFlagChecker $featureFlagChecker,
QtiItemResponseValidator $itemResponseValidator
) {
$this->runnerService = $runnerService;
$this->featureFlagChecker = $featureFlagChecker;
$this->itemResponseValidator = $itemResponseValidator;
}

public function save(ItemResponse $itemResponse, RunnerServiceContext $serviceContext): void
Expand Down Expand Up @@ -110,6 +120,17 @@ private function saveItemResponses(ItemResponse $itemResponse, RunnerServiceCont
$itemResponse->getResponse()
);

if ($this->featureFlagChecker->isEnabled('FEATURE_FLAG_RESPONSE_VALIDATOR')) {
try {
$this->itemResponseValidator->validate($serviceContext->getTestSession(), $responses);
} catch (AssessmentItemSessionException $e) {
throw new QtiRunnerInvalidResponsesException($e->getMessage());
}

$this->runnerService->storeItemResponse($serviceContext, $itemDefinition, $responses);
return;
}

if (
$this->runnerService->getTestConfig()->getConfigValue('enableAllowSkipping')
&& !TestRunnerUtils::doesAllowSkipping($serviceContext->getTestSession())
Expand Down
72 changes: 72 additions & 0 deletions model/Infrastructure/QtiItemResponseValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?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\model\Infrastructure;

use common_exception_Error;
use oat\taoQtiTest\models\runner\QtiRunnerEmptyResponsesException;
use oat\taoQtiTest\models\runner\RunnerServiceContext;
use qtism\runtime\common\State;
use qtism\runtime\tests\AssessmentItemSessionException;
use qtism\runtime\tests\AssessmentTestSession;

class QtiItemResponseValidator
{
/**
* @throws AssessmentItemSessionException
* @throws common_exception_Error
* @throws QtiRunnerEmptyResponsesException
*/
public function validate(AssessmentTestSession $testSession, State $responses): void
{
if ($this->getAllowSkip($testSession) && $responses->containsNullOnly()) {
return;
}

if (!$this->getAllowSkip($testSession) && $responses->containsNullOnly()) {
throw new QtiRunnerEmptyResponsesException();
}

if ($this->getResponseValidation($testSession)) {
$testSession->getCurrentAssessmentItemSession()
->checkResponseValidityConstraints($responses);
}
}

private function getResponseValidation(AssessmentTestSession $testSession): bool
{
return $testSession->getRoute()
->current()
->getItemSessionControl()
->getItemSessionControl()
->mustValidateResponses();
}

private function getAllowSkip(AssessmentTestSession $testSession): bool
{
return $testSession->getRoute()
->current()
->getItemSessionControl()
->getItemSessionControl()
->doesAllowSkipping();
}
}
92 changes: 92 additions & 0 deletions model/Service/PluginManagerService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?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\model\Service;

use common_ext_Extension;
use common_ext_ExtensionsManager as ExtensionsManager;
use oat\generis\model\data\Ontology;
use oat\oatbox\reporting\Report;

class PluginManagerService
{
private const PLUGIN_MAP = [
'allowSkipping' => 'enable-allow-skipping',
'validateResponses' => 'enable-validate-responses',
];
private Ontology $ontology;
private ExtensionsManager $extensionsManager;
private common_ext_Extension $extension;
private array $config;

public function __construct(Ontology $ontology, ExtensionsManager $extensionsManager)
{
$this->ontology = $ontology;
$this->extensionsManager = $extensionsManager;
$this->extension = $this->extensionsManager->getExtensionById('taoQtiTest');
$this->config = $this->extension->getConfig('testRunner') ?? [];
}

/**
* @param string[] $disablePlugins
* @param Report $report
* @throws \common_exception_Error
*/
public function disablePlugin(array $disablePlugins, Report $report): void
{
foreach ($disablePlugins as $plugin) {
if (array_key_exists($plugin, self::PLUGIN_MAP)) {
$report->add(new Report(Report::TYPE_INFO, 'Plugin ' . $plugin . ' has been disabled'));
$this->config[self::PLUGIN_MAP[$plugin]] = false;
}

if (array_key_exists($plugin, $this->config)) {
$report->add(new Report(Report::TYPE_INFO, 'Plugin ' . $plugin . ' has been disabled'));
$this->config[$plugin] = false;
}
}
$this->extension->setConfig('testRunner', $this->config);
}

public function enablePlugin(array $enablePlugins, Report $report): void
{
$config = $this->getConfig();

foreach ($enablePlugins as $plugin) {
if (array_key_exists($plugin, self::PLUGIN_MAP)) {
$report->add(new Report(Report::TYPE_INFO, 'Plugin ' . $plugin . ' has been enabled'));
$config[self::PLUGIN_MAP[$plugin]] = true;
}

if (array_key_exists($plugin, $config)) {
$report->add(new Report(Report::TYPE_INFO, 'Plugin ' . $plugin . ' has been disabled'));
$config[$plugin] = true;
}
}
$this->extension->setConfig('testRunner', $config);
}

private function getConfig(): array
{
return $this->extensionsManager->getExtensionById('taoQtiTest')->getConfig('testRunner');
}
}
37 changes: 37 additions & 0 deletions models/classes/runner/QtiRunnerInvalidResponsesException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?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 ;
*/

namespace oat\taoQtiTest\models\classes\runner;

use common_Exception;
use common_exception_UserReadableException;

class QtiRunnerInvalidResponsesException extends common_Exception implements common_exception_UserReadableException
{
public function __construct($message = 'A response to this item is invalid', $code = 200)
{
parent::__construct($message, $code);
}

public function getUserMessage()
{
return __('A response to this item is invalid.');
}
}
4 changes: 2 additions & 2 deletions models/classes/runner/time/QtiTimeConstraint.php
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ private function durationToMs($duration)
* Serialize the constraint the expected way by the TestContext and the TestMap
* @return array
*/
public function jsonSerialize()
public function jsonSerialize(): array
{
$source = $this->getSource();
$timeLimits = $source->getTimeLimits();
Expand Down Expand Up @@ -271,6 +271,6 @@ public function jsonSerialize()
];
}
}
return null;
return [];
}
}
Loading

0 comments on commit 82f46b7

Please sign in to comment.