Skip to content

Commit

Permalink
Merge pull request #339 from oat-sa/release-2.19.0
Browse files Browse the repository at this point in the history
Release 2.19.0
  • Loading branch information
llecaque committed Feb 12, 2016
2 parents f768204 + 5aab488 commit ed36e36
Show file tree
Hide file tree
Showing 17 changed files with 355 additions and 136 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,21 @@ extension-tao-testqti
=====================

Extension to create QTI tests into TAO


About the new test runner
=========================

The new test runner uses now a more consistent format for the config, but a mapping is made to convert the current server config to the new format. So if new entries are added to current config, the class has to be updated to support this new entry.

Now the review plugin is related to the item categories, so the category `x-tao-option-reviewScreen` need to be set on each navigable item. The mark for review button is related to the category `x-tao-option-markReview`

Here is a list of known category options:

| Option | Description |
| --- | --- |
| `x-tao-option-reviewScreen` | Enable the review/navigation panel |
| `x-tao-option-markReview` | Enable the mark for review button when the review/navigation panel is enabled |
| `x-tao-option-exit` | Allow to finish and exit the test |
| `x-tao-option-nextSection` | Enable the next section button |
| `x-tao-option-nextSectionWarning` | Enable the next section button, display a confirm message |
4 changes: 4 additions & 0 deletions actions/class.Runner.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use oat\taoQtiTest\models\runner\QtiRunnerServiceContext;
use oat\taoQtiTest\models\runner\QtiRunnerClosedException;
use oat\taoQtiTest\models\runner\QtiRunnerPausedException;
use oat\taoQtiTest\models\event\TraceVariableStored;

/**
* Class taoQtiTest_actions_Runner
Expand Down Expand Up @@ -677,6 +678,9 @@ public function storeTraceData(){
'success' => $stored == $size
];
common_Logger::d("Stored {$stored}/{$size} trace variables");
$eventManager = $this->getServiceManager()->get(\oat\oatbox\event\EventManager::CONFIG_ID);
$event = new TraceVariableStored($serviceContext->getTestSession()->getSessionId());
$eventManager->trigger($event);

} catch (common_Exception $e) {
$response = $this->getErrorResponse($e);
Expand Down
9 changes: 8 additions & 1 deletion config/default/testRunner.conf.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,16 @@
*/
'next-section' => false,

/**
/**
* After resuming test session timers will be reset to the time when the last item has been submitted.
* @type boolean
*/
'reset-timer-after-resume' => false,

/**
* Sets an extra AssessmentTestContext builder class.
* This class have to implements \oat\taoQtiTest\models\TestContextBuilder
* @type string
*/
'extraContextBuilder' => null,
);
18 changes: 18 additions & 0 deletions helpers/class.TestRunnerUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,24 @@ static public function buildAssessmentTestContext(AssessmentTestSession $session
$context[$contextKey] = $config[$configKey];
}
}

// optionally extend the context
if (isset($config['extraContextBuilder']) && class_exists($config['extraContextBuilder'])) {
$builder = new $config['extraContextBuilder']();
if ($builder instanceof \oat\taoQtiTest\models\TestContextBuilder) {
$builder->extendAssessmentTestContext(
$context,
$session,
$testMeta,
$qtiTestDefinitionUri,
$qtiTestCompilationUri,
$standalone,
$compilationDirs
);
} else {
common_Logger::i('Try to use an extra context builder class that is not an instance of \\oat\\taoQtiTest\\models\\TestContextBuilder!');
}
}
}

return $context;
Expand Down
37 changes: 36 additions & 1 deletion helpers/class.TestSession.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,41 @@ public function endTestSession() {

$this->triggerEventChange();
}

/**
* Rewind the test to its first position
* @param boolean $allowTimeout Whether or not it is allowed to jump if the timeLimits in force of the jump target are not respected.
* @throws AssessmentTestSessionException If $position is out of the Route bounds or the jump is not allowed because of time constraints.
*/
public function rewind($allowTimeout = false)
{
$position = 0;
$this->suspendItemSession();
$route = $this->getRoute();
$oldPosition = $route->getPosition();

try {
$route->setPosition($position);
$this->selectEligibleItems();

// Check the time limits after the jump is trully performed.
if ($allowTimeout === false) {
$this->checkTimeLimits(false, true);
}

// No exception thrown, interact!
$this->interactWithItemSession();
}
catch (AssessmentTestSessionException $e) {
// Rollback to previous position.
$route->setPosition($oldPosition);
throw $e;
}
catch (OutOfBoundsException $e) {
$msg = "Position '${position}' is out of the Route bounds.";
throw new AssessmentTestSessionException($msg, AssessmentTestSessionException::FORBIDDEN_JUMP, $e);
}
}

protected function submitTestResults() {
$testUri = $this->getTest()->getUri();
Expand Down Expand Up @@ -339,4 +374,4 @@ protected function getEventManager() {
protected function getServiceLocator() {
return ServiceManager::getServiceManager();
}
}
}
2 changes: 1 addition & 1 deletion manifest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
'label' => 'QTI test model',
'description' => 'TAO QTI test implementation',
'license' => 'GPL-2.0',
'version' => '2.18.0',
'version' => '2.19.0',
'author' => 'Open Assessment Technologies',
'requires' => array(
'taoTests' => '>=2.6',
Expand Down
50 changes: 50 additions & 0 deletions models/classes/TestContextBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?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) 2016 (original work) Open Assessment Technologies SA ;
*/

namespace oat\taoQtiTest\models;

use qtism\runtime\tests\AssessmentTestSession;

/**
* @author Jean-Sébastien Conan <[email protected]>
*/

/**
* Interface TestContextBuilder.
*
* Provides a way to extend the assessment test context.
*
* @package oat\taoQtiTest\models
*/
interface TestContextBuilder
{
/**
* Extends an already built context
*
* @param array $context A reference to the context to extend
* @param AssessmentTestSession $session A given AssessmentTestSession object.
* @param array $testMeta An associative array containing meta-data about the test definition taken by the candidate.
* @param string $qtiTestDefinitionUri The URI of a reference to an Assessment Test definition in the knowledge base.
* @param string $qtiTestCompilationUri The Uri of a reference to an Assessment Test compilation in the knowledge base.
* @param string $standalone
* @param string $compilationDirs An array containing respectively the private and public compilation directories.
* @return array The context of the candidate session.
*/
public function extendAssessmentTestContext(array &$context, AssessmentTestSession $session, array $testMeta, $qtiTestDefinitionUri, $qtiTestCompilationUri, $standalone, $compilationDirs);
}
47 changes: 23 additions & 24 deletions models/classes/TestSessionMetaData.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,17 @@

namespace oat\taoQtiTest\models;

use DateTime;
use alroniks\dtms\DateInterval;
use alroniks\dtms\DateTime;
use DateTimeZone;
use qtism\common\datatypes\Duration;
use qtism\data\AssessmentItemRef;
use qtism\data\ExtendedAssessmentItemRef;
use qtism\runtime\tests\AssessmentTestSession;
use qtism\common\enums\Cardinality;
use Context;
use taoResultServer_models_classes_TraceVariable;
use qtism\runtime\tests\AssessmentTestSessionState;

/**
* Class manages test session metadata such as section or test exit codes and other.
Expand Down Expand Up @@ -171,20 +174,19 @@ function ($item, $testSessionMetaData) {
};

return $a->longerThanOrEquals($b) ? 1 : - 1;

});

$startTimeSection = $testSessionMetaData->getStartSectionTime();//start time of first item in section

if (isset( $timeLimits[count($timeLimits) - 1] )) {
$maxAllowedTime = $timeLimits[count($timeLimits) - 1];//actually current limit for answering

$latestPossibleSectionTime = $startTimeSection->add(new \DateInterval('PT' . $maxAllowedTime->getSeconds() . 'S'));
$latestPossibleSectionTime = $startTimeSection->add(new DateInterval('PT' . $maxAllowedTime->getSeconds(true) . 'S'));

if ($time > $latestPossibleSectionTime->getTimestamp()) {
$currentItemRef = $this->getTestSession()->getCurrentAssessmentItemRef();
if ($itemMaxTimeAllowed) {
$time = $testSessionMetaData->getItemStartTime($currentItemRef)->add(new \DateInterval('PT' . $itemMaxTimeAllowed->getSeconds() . 'S'))->getTimestamp();
$time = $testSessionMetaData->getItemStartTime($currentItemRef)->add(new DateInterval('PT' . $itemMaxTimeAllowed->getSeconds(true) . 'S'))->getTimestamp();
} else {
$time = $latestPossibleSectionTime->getTimestamp();
}
Expand Down Expand Up @@ -229,32 +231,29 @@ public function getData()
{
$request = Context::getInstance()->getRequest();
$data = $request->hasParameter('metaData') ? $request->getParameter('metaData') : array();
$action = Context::getInstance()->getActionName();
$route = $this->getTestSession()->getRoute();

if (in_array($action, array('index'))) {
if ($route->getPosition() === 0) { //very first item
$data['TEST']['TAO_VERSION'] = TAO_VERSION;
}

if (in_array($action, array('moveForward', 'skip'))) {
if (!isset($data['SECTION']['SECTION_EXIT_CODE'])) {
$currentSection = $this->getTestSession()->getCurrentAssessmentSection();
$timeOut = \taoQtiTest_helpers_TestRunnerUtils::isTimeout($this->getTestSession());
$lastInSection = $route->isLast() ||
($route->getNext()->getAssessmentSection()->getIdentifier() !== $currentSection->getIdentifier());

if ($lastInSection && $timeOut) {
$data['SECTION']['SECTION_EXIT_CODE'] = self::SECTION_CODE_COMPLETE_TIMEOUT;
} elseif ($timeOut) {
$data['SECTION']['SECTION_EXIT_CODE'] = self::SECTION_CODE_TIMEOUT;
} elseif ($lastInSection) {
$data['SECTION']['SECTION_EXIT_CODE'] = self::SECTION_CODE_COMPLETED_NORMALLY;
}
if (!isset($data['SECTION']['SECTION_EXIT_CODE']) && $this->getTestSession()->getState() != AssessmentTestSessionState::INITIAL) {
$currentSection = $this->getTestSession()->getCurrentAssessmentSection();
$timeOut = \taoQtiTest_helpers_TestRunnerUtils::isTimeout($this->getTestSession());
$lastInSection = $route->isLast() ||
($route->getNext()->getAssessmentSection()->getIdentifier() !== $currentSection->getIdentifier());

if ($lastInSection && $timeOut) {
$data['SECTION']['SECTION_EXIT_CODE'] = self::SECTION_CODE_COMPLETE_TIMEOUT;
} elseif ($timeOut) {
$data['SECTION']['SECTION_EXIT_CODE'] = self::SECTION_CODE_TIMEOUT;
} elseif ($lastInSection) {
$data['SECTION']['SECTION_EXIT_CODE'] = self::SECTION_CODE_COMPLETED_NORMALLY;
}
}

if ($route->isLast()) {
$data['TEST']['TEST_EXIT_CODE'] = self::TEST_CODE_COMPLETE;
}
if ($route->isLast()) {
$data['TEST']['TEST_EXIT_CODE'] = self::TEST_CODE_COMPLETE;
}

return $data;
Expand Down Expand Up @@ -329,7 +328,7 @@ public function getItemStartTime($itemRef)
}

$itemResults = array_map(function ($ts) {
$itemStart = (new DateTime('now', new \DateTimeZone('UTC')));
$itemStart = (new DateTime('now', new DateTimeZone('UTC')));
$itemStart->setTimestamp($ts);

return $itemStart;
Expand Down
75 changes: 75 additions & 0 deletions models/classes/event/TraceVariableStored.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?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) 2015 (original work) Open Assessment Technologies SA;
*
*
*/

namespace oat\taoQtiTest\models\event;

use oat\oatbox\event\Event;
use oat\taoDelivery\model\execution\DeliveryExecution;
/**
* Event should be triggered after storing test trace variable
*
*/
class TraceVariableStored implements Event
{

private $deliveryExecutionId;

private $deliveryExecution;

/**
* DeliveryExecutionState constructor.
* @param $deliveryExecutionId
*/
public function __construct($deliveryExecutionId)
{
$this->deliveryExecutionId = $deliveryExecutionId;
}

/**
* @return DeliveryExecution
*/
public function getDeliveryExecution()
{
if(is_null($this->deliveryExecution)){
$this->deliveryExecution = \taoDelivery_models_classes_execution_ServiceProxy::singleton()->getDeliveryExecution($this->deliveryExecutionId);
}
return $this->deliveryExecution;
}

/**
* @return string
*/
public function getState()
{
$deliveryExecution = $this->getDeliveryExecution();
return $deliveryExecution->getState()->getUri();
}


/**
* @return string
*/
public function getName()
{
return __CLASS__;
}

}
Loading

0 comments on commit ed36e36

Please sign in to comment.