Commit c6d11f0f authored by Sara Arjona's avatar Sara Arjona
Browse files

MDL-72041 qformat: Remove WebCT question format

WebCT was acquired by Blackboard in 2006, so qformat_webct has been
completely removed from Moodle core.
parent 443a980a
...@@ -1725,6 +1725,7 @@ class core_plugin_manager { ...@@ -1725,6 +1725,7 @@ class core_plugin_manager {
'block' => array('course_overview', 'messages', 'community', 'participants'), 'block' => array('course_overview', 'messages', 'community', 'participants'),
'cachestore' => array('memcache'), 'cachestore' => array('memcache'),
'enrol' => array('authorize'), 'enrol' => array('authorize'),
'qformat' => array('webct'),
'quizaccess' => array('safebrowser'), 'quizaccess' => array('safebrowser'),
'report' => array('search'), 'report' => array('search'),
'repository' => array('alfresco'), 'repository' => array('alfresco'),
...@@ -1958,7 +1959,7 @@ class core_plugin_manager { ...@@ -1958,7 +1959,7 @@ class core_plugin_manager {
'qformat' => array( 'qformat' => array(
'aiken', 'blackboard_six', 'examview', 'gift', 'aiken', 'blackboard_six', 'examview', 'gift',
'missingword', 'multianswer', 'webct', 'missingword', 'multianswer',
'xhtml', 'xml' 'xhtml', 'xml'
), ),
......
...@@ -2707,5 +2707,15 @@ function xmldb_main_upgrade($oldversion) { ...@@ -2707,5 +2707,15 @@ function xmldb_main_upgrade($oldversion) {
upgrade_main_savepoint(true, 2021072800.01); upgrade_main_savepoint(true, 2021072800.01);
} }
if ($oldversion < 2021090200.01) {
// Remove qformat_webct (unless it has manually been added back).
if (!file_exists($CFG->dirroot . '/question/format/webct/format.php')) {
unset_all_config_for_plugin('qformat_webct');
}
// Main savepoint reached.
upgrade_main_savepoint(true, 2021090200.01);
}
return true; return true;
} }
This files describes API changes for question import/export format plugins. This files describes API changes for question import/export format plugins.
=== 4.0 ===
* The WebCT question format has been completely removed (WebCT was acquired by Blackboard in 2006).
=== 3.6 === === 3.6 ===
* Saving question category descriptions (info) is now supported in Moodle XML import/export format. * Saving question category descriptions (info) is now supported in Moodle XML import/export format.
......
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle 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, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Privacy Subsystem implementation for qformat_webct.
*
* @package qformat_webct
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace qformat_webct\privacy;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy Subsystem for qformat_webct implementing null_provider.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements \core_privacy\local\metadata\null_provider {
/**
* Get the language string identifier with the component's language
* file to explain why this plugin stores no data.
*
* @return string
*/
public static function get_reason() : string {
return 'privacy:metadata';
}
}
This diff is collapsed.
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle 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, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Strings for component 'qformat_webct', language 'en', branch 'MOODLE_20_STABLE'
*
* @package qformat_webct
* @copyright 2010 Helen Foster
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['errorsdetected'] = '{$a} error(s) detected';
$string['missinganswer'] = 'Too few :ANSWER, :Lx, :Rx statements for question line {$a}. You must define at least 2 possible answers.';
$string['missingquestion'] = 'Missing question label after line {$a}';
$string['pluginname'] = 'WebCT format';
$string['pluginname_help'] = 'WebCT format enables multiple-choice and short answer questions saved in WebCT\'s text-based format to be imported.';
$string['pluginname_link'] = 'qformat/webct';
$string['privacy:metadata'] = 'The WebCT question format plugin does not store any personal data.';
$string['questionnametoolong'] = 'Question name too long at line {$a} (255 char. max). It has been truncated.';
$string['unknowntype'] = 'Unknown question type after line {$a}';
$string['warningsdetected'] = '{$a} warning(s) detected';
$string['wronggrade'] = 'Wrong grade (after line {$a}) :';
@qformat @qformat_webct
Feature: Test importing questions from WebCT format.
In order to reuse questions from am obsolete commercial LMS
As an teacher
I need to be able to import them in WebCT format.
Background:
Given the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | topics |
And the following "users" exist:
| username | firstname |
| teacher | Teacher |
And the following "course enrolments" exist:
| user | course | role |
| teacher | C1 | editingteacher |
And I log in as "teacher"
And I am on "Course 1" course homepage
@javascript @_file_upload
Scenario: import some WebCT questions
When I navigate to "Question bank > Import" in current page administration
And I set the field "id_format_webct" to "1"
And I upload "question/format/webct/tests/fixtures/sample_webct.txt" file to "Import" filemanager
And I press "id_submitbutton"
Then I should see "Parsing questions from import file."
And I should see "Importing 6 questions from file"
And I should see "What's between orange and green in the spectrum?"
When I press "Continue"
Then I should see "USER-3"
@qformat @qformat_webct
Feature: Test importing calculated question from WebCT format.
In order to reuse calculated questions from a commercial LMS
As a teacher
I need to be able to import them in WebCT format.
Background:
Given the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | topics |
And the following "users" exist:
| username | firstname |
| teacher | Teacher |
And the following "course enrolments" exist:
| user | course | role |
| teacher | C1 | editingteacher |
And I log in as "teacher"
And I am on "Course 1" course homepage
@javascript @_file_upload
Scenario: import a WebCT calculated question
When I navigate to "Question bank > Import" in current page administration
And I set the field "id_format_webct" to "1"
And I upload "question/format/webct/tests/fixtures/sample_calculated_webct.txt" file to "Import" filemanager
And I press "id_submitbutton"
Then I should see "Parsing questions from import file."
And I should see "Importing 1 questions from file"
And I should see "Find the area in m2 of a square with sides of length {l} m."
When I press "Continue"
Then I should see "calculated: Square area"
# Start of calculated question: Square area
:TYPE:C
:TITLE:calculated: Square area
:QUESTION:H
Find the area in m<sup>2</sup> of a square with sides of length {l} m.
:IMAGE:
:FORMULA:{l}*{l}
:l-MIN:10
:l-MAX:100
:l-DEC:0
:VALUES:10
:l-VAL1:51
:l-VAL2:32
:l-VAL3:57
:l-VAL4:94
:l-VAL5:38
:l-VAL6:54
:l-VAL7:87
:l-VAL8:90
:l-VAL9:78
:l-VAL10:39
:ANS-DEC:1
:TOL:
:TOLTYPE:percent
:UNITREQ:0
:UNITSPACE:0
:UNITCASE:0
:UNITVAL:0
:ANSTYPE:dec
:FEEDBACK:H
:CAT:Import from WebCT
# End of calculated question: Square area
# Start of question:Question 001
:TYPE:MC:1:0:A
:TITLE:USER-1
:QUESTION:H
42 is the Absolute Answer to everything.
:LAYOUT:horizontal
:ANSWERORDER:randomized
:INDICES:letters
:ANSWER1:0:H
True
:REASON1:H
42 is the <b>Ultimate</b> Answer.
:ANSWER2:100:H
False
:REASON2:H
42 is the <b>Ultimate</b> Answer.
:CAT:webct
:ASSESSMENT:Test
# End of question:Question 001
# Start of question:Question 002
:TYPE:MC:1:0:A
:TITLE:USER-2
:QUESTION:H
<font size="+1">What's between orange and green in the spectrum?</font>
:LAYOUT:horizontal
:ANSWERORDER:randomized
:INDICES:letters
:ANSWER1:0:H
red
:REASON1:H
Red is not between orange and green in the spectrum but yellow is.
:ANSWER2:100:H
yellow
:REASON2:H
You gave the right answer.
:ANSWER3:0:H
blue
:REASON3:H
Blue is not between orange and green in the spectrum but yellow is.
:CAT:webct
:ASSESSMENT:Test
# End of question:Question 002
# Start of question:Question 003
:TYPE:MC:N:0:A
:TITLE:USER-3
:QUESTION:H
<i>What's between orange and green in the spectrum?</i>
:LAYOUT:horizontal
:ANSWERORDER:randomized
:INDICES:letters
:ANSWER1:50:H
yellow
:REASON1:H
True, yellow is between orange and green in the spectrum,
:ANSWER2:0:H
red
:REASON2:H
False, red is not between orange and green in the spectrum,
:ANSWER3:50:H
off-beige
:REASON3:H
True, off-beige is between orange and green in the spectrum,
:ANSWER4:0:H
blue
:REASON4:H
False, red is not between orange and green in the spectrum,
:CAT:webct
:ASSESSMENT:Test
# End of question:Question 003
# Start of question:Question 004
:TYPE:M:short:short:E:0
:TITLE:Classify the animals.
:QUESTION:H
<i>Classify the animals.</i>
:IMAGE:
:L1
cat
:R1
mammal
:L2
frog
:R2
amphibian
:L3
newt
:R3
amphibian
:CAT:Ch 00 Instr Test Items
:ASSESSMENT:Test
# End of question:Question 004
# Start of question:Question 005
:TYPE:S
:TITLE:USER-5
:QUESTION:H
Name an amphibian&#58; __________
:ANSWERS:1
:ANSWER1:frog:100:0:20:0
:FEEDBACK1:H
A frog is an amphibian
:CAT:webct
:ASSESSMENT:Test
# End of question:Question 005
# Start of question:Question 006
:TYPE:P
:TITLE:USER-6
:QUESTION:H:60:5
How are you?
:ANSWER:H
Blackboard answer for essay questions will be imported as informations for graders.
:CAT:webct
:ASSESSMENT:Test
# End of question:Question 006
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle 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, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Unit tests for Web CT question importer.
*
* @package qformat_webct
* @copyright 2013 Jean-Michel Vedrine
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir . '/questionlib.php');
require_once($CFG->dirroot . '/question/format.php');
require_once($CFG->dirroot . '/question/format/webct/format.php');
require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
/**
* Unit tests for the webct question import format.
*
* @copyright 2013 Jean-Michel Vedrine
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qformat_webct_test extends question_testcase {
public function make_test() {
$lines = file(__DIR__ . '/fixtures/sample_webct.txt');
return $lines;
}
public function test_import_match() {
$txt = $this->make_test();
$importer = new qformat_webct();
$questions = $importer->readquestions($txt);
$q = $questions[3];
$expectedq = new stdClass();
$expectedq->qtype = 'match';
$expectedq->name = 'Classify the animals.';
$expectedq->questiontext = '<i>Classify the animals.</i>';
$expectedq->questiontextformat = FORMAT_HTML;
$expectedq->correctfeedback = array(
'text' => '',
'format' => FORMAT_HTML,
'files' => array(),
);
$expectedq->partiallycorrectfeedback = array(
'text' => '',
'format' => FORMAT_HTML,
'files' => array(),
);
$expectedq->incorrectfeedback = array(
'text' => '',
'format' => FORMAT_HTML,
'files' => array(),
);
$expectedq->generalfeedback = '';
$expectedq->generalfeedbackformat = FORMAT_MOODLE;
$expectedq->defaultmark = 1;
$expectedq->length = 1;
$expectedq->penalty = 0.3333333;
$expectedq->shuffleanswers = get_config('quiz', 'shuffleanswers');
$expectedq->subquestions = array(
1 => array('text' => 'cat', 'format' => FORMAT_HTML),
2 => array('text' => 'frog', 'format' => FORMAT_HTML),
3 => array('text' => 'newt', 'format' => FORMAT_HTML));
$expectedq->subanswers = array(1 => 'mammal', 2 => 'amphibian', 3 => 'amphibian');
$this->assert(new question_check_specified_fields_expectation($expectedq), $q);
}
public function test_import_multichoice_single() {
$txt = $this->make_test();
$importer = new qformat_webct();
$questions = $importer->readquestions($txt);
$q = $questions[1];
$expectedq = new stdClass();
$expectedq->qtype = 'multichoice';
$expectedq->single = 1;
$expectedq->name = 'USER-2';
$expectedq->questiontext = '<font size="+1">What\'s between orange and green in the spectrum?</font>';
$expectedq->questiontextformat = FORMAT_HTML;
$expectedq->correctfeedback = array(
'text' => '',
'format' => FORMAT_HTML,
'files' => array(),
);
$expectedq->partiallycorrectfeedback = array(
'text' => '',
'format' => FORMAT_HTML,
'files' => array(),
);
$expectedq->incorrectfeedback = array(
'text' => '',
'format' => FORMAT_HTML,
'files' => array(),
);
$expectedq->generalfeedback = '';
$expectedq->generalfeedbackformat = FORMAT_MOODLE;
$expectedq->defaultmark = 1;
$expectedq->length = 1;
$expectedq->penalty = 0.3333333;
$expectedq->shuffleanswers = get_config('quiz', 'shuffleanswers');
$expectedq->answer = array(
1 => array(
'text' => 'red',
'format' => FORMAT_HTML,
),
2 => array(
'text' => 'yellow',
'format' => FORMAT_HTML,
),
3 => array(
'text' => 'blue',
'format' => FORMAT_HTML,
)
);
$expectedq->fraction = array(
1 => 0,
2 => 1,
3 => 0,
);
$expectedq->feedback = array(
1 => array(
'text' => 'Red is not between orange and green in the spectrum but yellow is.',
'format' => FORMAT_HTML,
),
2 => array(
'text' => 'You gave the right answer.',
'format' => FORMAT_HTML,
),
3 => array(
'text' => 'Blue is not between orange and green in the spectrum but yellow is.',
'format' => FORMAT_HTML,
)
);
$this->assert(new question_check_specified_fields_expectation($expectedq), $q);
}
public function test_import_multichoice_multi() {
$txt = $this->make_test();
$importer = new qformat_webct();
$questions = $importer->readquestions($txt);
$q = $questions[2];
$expectedq = new stdClass();
$expectedq->qtype = 'multichoice';
$expectedq->single = 0;
$expectedq->name = 'USER-3';
$expectedq->questiontext = '<i>What\'s between orange and green in the spectrum?</i>';
$expectedq->questiontextformat = FORMAT_HTML;
$expectedq->correctfeedback = array(
'text' => '',
'format' => FORMAT_HTML,
'files' => array(),
);
$expectedq->partiallycorrectfeedback = array(
'text' => '',
'format' => FORMAT_HTML,
'files' => array(),
);
$expectedq->incorrectfeedback = array(
'text' => '',
'format' => FORMAT_HTML,
'files' => array(),
);
$expectedq->generalfeedback = '';
$expectedq->generalfeedbackformat = FORMAT_MOODLE;
$expectedq->defaultmark = 1;
$expectedq->length = 1;
$expectedq->penalty = 0.3333333;
$expectedq->shuffleanswers = get_config('quiz', 'shuffleanswers');
$expectedq->answer = array(
1 => array(
'text' => 'yellow',
'format' => FORMAT_HTML,
),
2 => array(
'text' => 'red',
'format' => FORMAT_HTML,
),
3 => array(
'text' => 'off-beige',
'format' => FORMAT_HTML,
),
4 => array(
'text' => 'blue',
'format' => FORMAT_HTML,
)
);
$expectedq->fraction = array(
1 => 0.5,
2 => 0,
3 => 0.5,
4 => 0,
);
$expectedq->feedback = array(
1 => array(
'text' => 'True, yellow is between orange and green in the spectrum,',
'format' => FORMAT_HTML,
),
2 => array(
'text' => 'False, red is not between orange and green in the spectrum,',
'format' => FORMAT_HTML,
),
3 => array(
'text' => 'True, off-beige is between orange and green in the spectrum,',
'format' => FORMAT_HTML,
),
4 => array(
'text' => 'False, red is not between orange and green in the spectrum,',
'format' => FORMAT_HTML,
)
);
$this->assert(new question_check_specified_fields_expectation($expectedq), $q);
}
public function test_import_truefalse() {
$txt = $this->make_test();
$importer = new qformat_webct();
$questions = $importer->readquestions($txt);
$q = $questions[0];
$expectedq = new stdClass();
$expectedq->qtype = 'multichoice';
$expectedq->single = 1;
$expectedq->name = 'USER-1';
$expectedq->questiontext = '42 is the Absolute Answer to everything.';
$expectedq->questiontextformat = FORMAT_HTML;
$expectedq->correctfeedback = array(