MDL-71378 core_question & mod_quiz: Refactor deprecated contexts

This commit is contained in:
Simon Adams
2024-11-18 10:22:59 +00:00
parent 5955868d3d
commit a0cf3d2da5
183 changed files with 1266 additions and 2721 deletions
@@ -0,0 +1,17 @@
issueNumber: MDL-71378
notes:
tool_brickfield:
- message: >
tool_brickfield\local\areas\core_question\answerbase::find_system_areas
No replacement. System context no longer a valid context to assign a
question category
type: deprecated
- message: >
tool_brickfield\local\areas\core_question\base::find_system_areas
No replacement. System context no longer a valid context to assign a
question category
type: deprecated
@@ -0,0 +1,42 @@
issueNumber: MDL-71378
notes:
core:
- message: >
question_make_default_categories()
No longer creates a default category in either CONTEXT_SYSTEM,
CONTEXT_COURSE, or CONTEXT_COURSECAT.
Superceded by question_get_default_category which can optionally create one if it does not exist.
type: deprecated
- message: |
question_delete_course()
No replacement. Course contexts no longer hold question categories.
type: deprecated
- message: |
question_delete_course_category()
Course category contexts no longer hold question categories.
type: deprecated
qbank_bulkmove:
- message: >
qbank_bulkmove/helper::get_displaydata
Superceded by a modal and webservice, see
qbank_bulkmove/modal_question_bank_bulkmove and
core_question_external\move_questions
type: deprecated
- message: |
qbank_bulkmove\output\renderer::render_bulk_move_form
Superceded by qbank_bulkmove\output\bulk_move
type: deprecated
core_question:
- message: |
question_type::generate_test
No replacement, not used anywhere in core.
type: deprecated
@@ -82,8 +82,12 @@ abstract class answerbase extends base {
* question categories at the system context, or course category context.
*
* @return mixed
* @deprecated since Moodle 5.0.
* @todo MDL-82413 Final deprecation in Moodle 6.0.
*/
#[\core\attribute\deprecated(null, since: '5.0', reason: 'This method should not be used', mdl: 'MDL-71378')]
public function find_system_areas(): ?\moodle_recordset {
\core\deprecation::emit_deprecation_if_present([self::class, __FUNCTION__]);
global $DB;
$params = [
'syscontext' => CONTEXT_SYSTEM,
@@ -132,8 +136,6 @@ abstract class answerbase extends base {
$coursecontext = \context_course::instance($courseid);
$param = [
'ctxcourse' => CONTEXT_COURSE,
'courseid' => $courseid,
'module' => CONTEXT_MODULE,
'coursecontextpath' => $DB->sql_like_escape($coursecontext->path) . '/%',
];
@@ -157,11 +159,8 @@ abstract class answerbase extends base {
ON qc.id = qbe.questioncategoryid
INNER JOIN {context} ctx
ON ctx.id = qc.contextid
WHERE (ctx.contextlevel = :ctxcourse
AND ctx.id = qc.contextid
AND ctx.instanceid = :courseid)
OR (ctx.contextlevel = :module
AND {$DB->sql_like('ctx.path', ':coursecontextpath')})
WHERE ctx.contextlevel = :module
AND {$DB->sql_like('ctx.path', ':coursecontextpath')}
ORDER BY a.id ASC";
return $DB->get_recordset_sql($sql, $param);
@@ -74,8 +74,6 @@ abstract class base extends area_base {
global $DB;
$coursecontext = \context_course::instance($courseid);
$param = [
'ctxcourse' => CONTEXT_COURSE,
'courseid' => $courseid,
'module' => CONTEXT_MODULE,
'coursecontextpath' => $DB->sql_like_escape($coursecontext->path) . '/%',
];
@@ -96,11 +94,8 @@ abstract class base extends area_base {
ON qc.id = qbe.questioncategoryid
INNER JOIN {context} ctx
ON ctx.id = qc.contextid
WHERE (ctx.contextlevel = :ctxcourse
AND ctx.id = qc.contextid
AND ctx.instanceid = :courseid)
OR (ctx.contextlevel = :module
AND {$DB->sql_like('ctx.path', ':coursecontextpath')})
WHERE ctx.contextlevel = :module
AND {$DB->sql_like('ctx.path', ':coursecontextpath')}
ORDER BY q.id ASC";
return $DB->get_recordset_sql($sql, $param);
@@ -111,8 +106,12 @@ abstract class base extends area_base {
* question categories at the system context only.
*
* @return \moodle_recordset
* @deprecated since Moodle 5.0.
* @todo MDL-82413 Final deprecation in Moodle 6.0.
*/
#[\core\attribute\deprecated(null, since: '5.0', reason: 'This method should not be used', mdl: 'MDL-71378')]
public function find_system_areas(): ?\moodle_recordset {
\core\deprecation::emit_deprecation_if_present([self::class, __FUNCTION__]);
global $DB;
$params = [
'syscontext' => CONTEXT_SYSTEM,
@@ -175,15 +174,7 @@ abstract class base extends area_base {
$catid = 'null';
if ($record = self::get_course_and_category(CONTEXT_MODULE, $event->objectid)) {
if ($record->contextlevel == CONTEXT_MODULE) {
$courseid = $record->courseid;
} else if ($record->contextlevel == CONTEXT_COURSE) {
$courseid = $record->instanceid;
} else if ($record->contextlevel == CONTEXT_COURSECAT) {
$catid = $record->instanceid;
} else if ($record->contextlevel == CONTEXT_SYSTEM) {
$courseid = 1;
}
$courseid = $record->courseid;
}
return "
@@ -202,6 +193,10 @@ abstract class base extends area_base {
public static function get_course_and_category($coursemodule, $refid) {
global $DB;
if ($coursemodule !== CONTEXT_MODULE) {
debugging("Invalid contextlevel: ($coursemodule}", DEBUG_DEVELOPER);
}
$sql = 'SELECT ctx.instanceid,
cm.course as courseid,
ctx.contextlevel
@@ -214,7 +209,7 @@ abstract class base extends area_base {
ON qc.id = qbe.questioncategoryid
INNER JOIN {context} ctx
ON ctx.id = qc.contextid
LEFT JOIN {course_modules} cm
INNER JOIN {course_modules} cm
ON cm.id = ctx.instanceid
AND ctx.contextlevel = :coursemodule
WHERE q.id = :refid';
+12 -32
View File
@@ -93,51 +93,30 @@ class area_test extends area_test_base {
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
$component = 'core_question';
list($category1, $course1, $qcat1, $questions1) = $generator->setup_course_and_questions('course');
list($category2, $course2, $qcat2, $questions2) = $generator->setup_course_and_questions('category');
list($category3, $course3, $qcat3, $questions3) = $generator->setup_course_and_questions('system');
[$category, $course, $qcat, $questions, $qbank] = $generator->setup_course_and_questions();
$c = new \tool_brickfield\local\areas\core_question\questiontext();
// Set up results arrays from the recordset for easier testing.
$course1areas = $this->array_from_recordset($c->find_course_areas($course1->id));
$course2areas = $c->find_course_areas($course2->id);
$course3areas = $c->find_course_areas($course3->id);
$sysareas = $this->array_from_recordset($c->find_system_areas());
$course1areas = $this->array_from_recordset($c->find_course_areas($course->id));
// Assert the core_question area exists for the individual question's context, courseid and categoryid.
// Assert the core_question area exists for the individual question's context, courseid and categoryid.
$this->assert_area_in_array(
$course1areas,
$component,
\context_course::instance($course1->id)->id,
$questions1[0]->id,
$course1->id,
null
);
$this->assert_area_in_array(
$sysareas,
$component,
\context_coursecat::instance($category2->id)->id,
$questions2[0]->id,
SITEID,
$category2->id
);
$this->assert_area_in_array(
$sysareas,
$component,
\context_system::instance()->id,
$questions3[0]->id,
SITEID,
\context_module::instance($qbank->cmid)->id,
$questions[0]->id,
$course->id,
null
);
// Emulate the question_created event.
$event = \core\event\question_created::create_from_question_instance($questions1[1],
\context_course::instance($course1->id));
$event = \core\event\question_created::create_from_question_instance($questions[1],
\context_module::instance($qbank->cmid));
$relevantresults = $this->array_from_recordset($c->find_relevant_areas($event));
$this->assert_area_in_array(
$course1areas,
$relevantresults,
$component,
\context_course::instance($relevantresults[0]->courseid)->id,
$relevantresults[0]->contextid,
$relevantresults[0]->itemid,
$relevantresults[0]->courseid,
$relevantresults[0]->categoryid
@@ -154,7 +133,8 @@ class area_test extends area_test_base {
/** @var \core_question_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
$course = $this->getDataGenerator()->create_course();
$cat = $generator->create_question_category(['contextid' => \context_course::instance($course->id)->id]);
$qbank = $this->getDataGenerator()->create_module('qbank', ['course' => $course->id]);
$cat = $generator->create_question_category(['contextid' => \context_module::instance($qbank->cmid)->id]);
$question1 = $generator->create_question('multichoice', null,
['name' => 'Example multichoice question', 'category' => $cat->id]);
$question2 = $generator->create_question('numerical', null,
@@ -34,92 +34,6 @@ class questionanswers_test extends \advanced_testcase {
parent::setUpBeforeClass();
}
/**
* Test find course areas.
*/
public function test_find_course_areas(): void {
$this->resetAfterTest();
$this->setAdminUser();
$category = $this->getDataGenerator()->create_category();
$course = $this->getDataGenerator()->create_course(['category' => $category->id]);
$coursecontext = \context_course::instance($course->id);
$catcontext = \context_coursecat::instance($category->id);
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
$cat1 = $generator->create_question_category(['contextid' => $coursecontext->id]);
$question1 = $generator->create_question('multichoice', null, ['category' => $cat1->id]);
$question2 = $generator->create_question('multichoice', null, ['category' => $cat1->id]);
$questionanswers = new questionanswers();
$rs = $questionanswers->find_course_areas($course->id);
$this->assertNotNull($rs);
// Each multichoice question generated has four answers. So there should be eight records.
$count = 0;
foreach ($rs as $rec) {
$count++;
$this->assertEquals($coursecontext->id, $rec->contextid);
$this->assertEquals($course->id, $rec->courseid);
if ($count <= 4) {
$this->assertEquals($question1->id, $rec->refid);
} else {
$this->assertEquals($question2->id, $rec->refid);
}
}
$rs->close();
$this->assertEquals(8, $count);
// Add a question to a quiz in the course.
$quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id, 'name' => 'Quiz1']);
$quizmodule = get_coursemodule_from_instance('quiz', $quiz->id, $course->id);
$quizcontext = \context_module::instance($quizmodule->id);
// Add a question to the quiz context.
$cat2 = $generator->create_question_category(['contextid' => $quizcontext->id]);
$question3 = $generator->create_question('multichoice', null, ['category' => $cat2->id]);
$rs2 = $questionanswers->find_course_areas($course->id);
$this->assertNotNull($rs2);
// Each multichoice question generated has four answers. So there should be twelve records now.
$count = 0;
foreach ($rs2 as $rec) {
$count++;
if ($count <= 4) {
$this->assertEquals($coursecontext->id, $rec->contextid);
$this->assertEquals($course->id, $rec->courseid);
$this->assertEquals($question1->id, $rec->refid);
} else if ($count <= 8) {
$this->assertEquals($coursecontext->id, $rec->contextid);
$this->assertEquals($course->id, $rec->courseid);
$this->assertEquals($question2->id, $rec->refid);
} else {
$this->assertEquals($quizcontext->id, $rec->contextid);
$this->assertEquals($course->id, $rec->courseid);
$this->assertEquals($question3->id, $rec->refid);
}
}
$rs2->close();
$this->assertEquals(12, $count);
// Add a question to the category context.
$cat3 = $generator->create_question_category(['contextid' => $catcontext->id]);
$question4 = $generator->create_question('multichoice', null, ['category' => $cat3->id]);
$rs3 = $questionanswers->find_course_areas($course->id);
$this->assertNotNull($rs3);
// The category level questions should not be found.
$count = 0;
foreach ($rs3 as $rec) {
$count++;
if ($count > 8) {
$this->assertEquals($quizcontext->id, $rec->contextid);
$this->assertEquals($course->id, $rec->courseid);
$this->assertEquals($question3->id, $rec->refid);
}
}
$rs2->close();
$this->assertEquals(12, $count);
}
/**
* Test find relevant areas.
*/
@@ -128,9 +42,10 @@ class questionanswers_test extends \advanced_testcase {
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$coursecontext = \context_course::instance($course->id);
$qbank = $this->getDataGenerator()->create_module('qbank', ['course' => $course->id]);
$qbankcontext = \context_module::instance($qbank->cmid);
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
$cat1 = $generator->create_question_category(['contextid' => $coursecontext->id]);
$cat1 = $generator->create_question_category(['contextid' => $qbankcontext->id]);
$question1 = $generator->create_question('multichoice', null, ['category' => $cat1->id]);
$question2 = $generator->create_question('multichoice', null, ['category' => $cat1->id]);
$questionanswers = new questionanswers();
@@ -143,50 +58,11 @@ class questionanswers_test extends \advanced_testcase {
$count = 0;
foreach ($rs as $rec) {
$count++;
$this->assertEquals($coursecontext->id, $rec->contextid);
$this->assertEquals($qbankcontext->id, $rec->contextid);
$this->assertEquals($course->id, $rec->courseid);
$this->assertEquals($question1->id, $rec->refid);
}
$rs->close();
$this->assertEquals(4, $count);
}
/**
* Test find system areas.
*/
public function test_find_system_areas(): void {
$this->resetAfterTest();
$this->setAdminUser();
$category = $this->getDataGenerator()->create_category();
$catcontext = \context_coursecat::instance($category->id);
$systemcontext = \context_system::instance();
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
$cat = $generator->create_question_category(['contextid' => $catcontext->id]);
$cat2 = $generator->create_question_category(['contextid' => $systemcontext->id]);
$question = $generator->create_question('multichoice', null, ['category' => $cat2->id]);
$question2 = $generator->create_question('multichoice', null, ['category' => $cat->id]);
$questionanswers = new questionanswers();
$rs = $questionanswers->find_system_areas();
$this->assertNotNull($rs);
// Each multichoice question generated has four answers.
$count = 0;
foreach ($rs as $rec) {
$count++;
if ($count <= 4) {
$this->assertEquals($systemcontext->id, $rec->contextid);
$this->assertEquals(1, $rec->courseid);
$this->assertEquals(0, $rec->categoryid);
$this->assertEquals($question->id, $rec->refid);
} else {
$this->assertEquals($catcontext->id, $rec->contextid);
$this->assertEquals(1, $rec->courseid);
$this->assertEquals($category->id, $rec->categoryid);
$this->assertEquals($question2->id, $rec->refid);
}
}
$rs->close();
$this->assertEquals(8, $count);
}
}
@@ -40,90 +40,6 @@ class questiontext_test extends area_test_base {
parent::setUpBeforeClass();
}
/**
* Test find course areas.
*/
public function test_find_course_areas(): void {
$this->resetAfterTest();
$this->setAdminUser();
$category = $this->getDataGenerator()->create_category();
$course = $this->getDataGenerator()->create_course(['category' => $category->id]);
$coursecontext = \context_course::instance($course->id);
$catcontext = \context_coursecat::instance($category->id);
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
$cat1 = $generator->create_question_category(['contextid' => $coursecontext->id]);
$question1 = $generator->create_question('multichoice', null, ['category' => $cat1->id]);
$question2 = $generator->create_question('multichoice', null, ['category' => $cat1->id]);
$questiontext = new questiontext();
$rs = $questiontext->find_course_areas($course->id);
$this->assertNotNull($rs);
$count = 0;
foreach ($rs as $rec) {
$count++;
$this->assertEquals($coursecontext->id, $rec->contextid);
$this->assertEquals($course->id, $rec->courseid);
if ($count <= 1) {
$this->assertEquals($question1->id, $rec->itemid);
} else {
$this->assertEquals($question2->id, $rec->itemid);
}
}
$rs->close();
$this->assertEquals(2, $count);
// Add a question to a quiz in the course.
$quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id, 'name' => 'Quiz1']);
$quizmodule = get_coursemodule_from_instance('quiz', $quiz->id, $course->id);
$quizcontext = \context_module::instance($quizmodule->id);
// Add a question to the quiz context.
$cat2 = $generator->create_question_category(['contextid' => $quizcontext->id]);
$question3 = $generator->create_question('multichoice', null, ['category' => $cat2->id]);
$rs2 = $questiontext->find_course_areas($course->id);
$this->assertNotNull($rs2);
$count = 0;
foreach ($rs2 as $rec) {
$count++;
if ($count <= 1) {
$this->assertEquals($coursecontext->id, $rec->contextid);
$this->assertEquals($course->id, $rec->courseid);
$this->assertEquals($question1->id, $rec->itemid);
} else if ($count <= 2) {
$this->assertEquals($coursecontext->id, $rec->contextid);
$this->assertEquals($course->id, $rec->courseid);
$this->assertEquals($question2->id, $rec->itemid);
} else {
$this->assertEquals($quizcontext->id, $rec->contextid);
$this->assertEquals($course->id, $rec->courseid);
$this->assertEquals($question3->id, $rec->itemid);
}
}
$rs2->close();
$this->assertEquals(3, $count);
// Add a question to the category context.
$cat3 = $generator->create_question_category(['contextid' => $catcontext->id]);
$question4 = $generator->create_question('multichoice', null, ['category' => $cat3->id]);
$rs3 = $questiontext->find_course_areas($course->id);
$this->assertNotNull($rs3);
// The category level questions should not be found.
$count = 0;
foreach ($rs3 as $rec) {
$count++;
if ($count > 2) {
$this->assertEquals($quizcontext->id, $rec->contextid);
$this->assertEquals($course->id, $rec->courseid);
$this->assertEquals($question3->id, $rec->itemid);
}
}
$rs2->close();
$this->assertEquals(3, $count);
}
/**
* Test find relevant areas.
*/
@@ -132,9 +48,10 @@ class questiontext_test extends area_test_base {
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$coursecontext = \context_course::instance($course->id);
$qbank = $this->getDataGenerator()->create_module('qbank', ['course' => $course->id]);
$qbankcontext = \context_module::instance($qbank->cmid);
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
$cat1 = $generator->create_question_category(['contextid' => $coursecontext->id]);
$cat1 = $generator->create_question_category(['contextid' => $qbankcontext->id]);
$question1 = $generator->create_question('multichoice', null, ['category' => $cat1->id]);
$question2 = $generator->create_question('multichoice', null, ['category' => $cat1->id]);
$questiontext = new questiontext();
@@ -146,7 +63,7 @@ class questiontext_test extends area_test_base {
$count = 0;
foreach ($rs as $rec) {
$count++;
$this->assertEquals($coursecontext->id, $rec->contextid);
$this->assertEquals($qbankcontext->id, $rec->contextid);
$this->assertEquals($course->id, $rec->courseid);
$this->assertEquals($question1->id, $rec->itemid);
}
@@ -154,45 +71,6 @@ class questiontext_test extends area_test_base {
$this->assertEquals(1, $count);
}
/**
* Test find system areas.
*/
public function test_find_system_areas(): void {
$this->resetAfterTest();
$this->setAdminUser();
$category = $this->getDataGenerator()->create_category();
$catcontext = \context_coursecat::instance($category->id);
$systemcontext = \context_system::instance();
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
$component = 'core_question';
$cat = $generator->create_question_category(['contextid' => $catcontext->id]);
$cat2 = $generator->create_question_category(['contextid' => $systemcontext->id]);
$question = $generator->create_question('multichoice', null, ['category' => $cat2->id]);
$question2 = $generator->create_question('multichoice', null, ['category' => $cat->id]);
$questiontext = new questiontext();
$areas = $this->array_from_recordset($questiontext->find_system_areas());
// Assert the core_question area exists for the individual question's context, courseid and categoryid.
$this->assert_area_in_array(
$areas,
$component,
$systemcontext->id,
$question->id,
SITEID,
null
);
$this->assert_area_in_array(
$areas,
$component,
$catcontext->id,
$question2->id,
SITEID,
$category->id
);
}
/**
* Test get course and category.
*
@@ -203,21 +81,18 @@ class questiontext_test extends area_test_base {
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$coursecontext = \context_course::instance($course->id);
$qbank = $this->getDataGenerator()->create_module('qbank', ['course' => $course->id]);
$qbankcontext = \context_module::instance($qbank->cmid);
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
$cat1 = $generator->create_question_category(['contextid' => $coursecontext->id]);
$cat1 = $generator->create_question_category(['contextid' => $qbankcontext->id]);
$question1 = $generator->create_question('multichoice', null, ['category' => $cat1->id]);
$event = \core\event\question_updated::create_from_question_instance($question1,
\context_course::instance($course->id));
$rs = base::get_course_and_category(CONTEXT_COURSE, $event->objectid);
$event = \core\event\question_updated::create_from_question_instance($question1, $qbankcontext);
$rs = base::get_course_and_category(CONTEXT_MODULE, $event->objectid);
$this->assertNotNull($rs);
$this->assertEquals(CONTEXT_COURSE, $rs->contextlevel);
$this->assertNotEquals(CONTEXT_MODULE, $rs->contextlevel);
// Invalid objectid.
$this->assertEquals(CONTEXT_MODULE, $rs->contextlevel);
// Invalid objectid and contextlevel.
$rs = base::get_course_and_category(CONTEXT_COURSE, 0);
$this->assertFalse($rs);
// Incorrect objectid.
$rs = base::get_course_and_category(CONTEXT_COURSE, 100);
$this->assertFalse($rs);
$this->assertDebuggingCalled();
}
}
+10 -2
View File
@@ -5119,7 +5119,14 @@ class restore_create_categories_and_questions extends restore_structure_step {
// As we can't create a 'Top' category in CONTEXT_COURSE we'll make a default
// qbank module and map it to that until they are created later.
if (empty($mapping->info->parent) && $before35) {
$top = question_get_top_category($data->contextid, true);
if ($context->contextlevel === CONTEXT_COURSE) {
$course = get_course($context->instanceid);
$defaultbank = \core_question\local\bank\question_bank_helper::get_default_open_instance_system_type($course, true);
$bankcontextid = $defaultbank->context->id;
} else {
$bankcontextid = $data->contextid;
}
$top = question_get_top_category($bankcontextid, true);
$data->parent = $top->id;
}
@@ -5426,8 +5433,9 @@ class restore_create_categories_and_questions extends restore_structure_step {
$newparent = 0; // No ctx match for both cats, no parent relationship
}
}
$context = \core\context::instance_by_id($dbcat->contextid);
// Here with $newparent empty, problem with contexts or remapping, set it to top cat
if (!$newparent && $dbcat->parent) {
if (!$newparent && $dbcat->parent && $context->contextlevel === CONTEXT_MODULE) {
$topcat = question_get_top_category($dbcat->contextid, true);
if ($dbcat->parent != $topcat->id) {
$DB->set_field('question_categories', 'parent', $topcat->id, array('id' => $dbcat->id));
-9
View File
@@ -2056,9 +2056,6 @@ class core_course_category implements renderable, cacheable_object, IteratorAggr
if (!$cb->delete_contents($this->get_context())) {
throw new moodle_exception('errordeletingcontentfromcategory', 'contentbank', '', $this->get_formatted_name());
}
if (!question_delete_course_category($this, null)) {
throw new moodle_exception('cannotdeletecategoryquestions', '', '', $this->get_formatted_name());
}
// Delete all events in the category.
$DB->delete_records('event', array('categoryid' => $this->id));
@@ -2245,12 +2242,6 @@ class core_course_category implements renderable, cacheable_object, IteratorAggr
);
}
}
if (!question_delete_course_category($this, $newparentcat)) {
if ($showfeedback) {
echo $OUTPUT->notification(get_string('errordeletingquestionsfromcategory', 'question', $catname), 'notifysuccess');
}
return false;
}
// Finally delete the category and it's context.
$categoryrecord = $this->get_db_record();
+3 -1
View File
@@ -65,7 +65,6 @@ $string['cannotcreateuploaddir'] = 'Cannot create upload folder. The site admini
$string['cannotcustomisefiltersblockuser'] = 'You cannot customise filters settings in user or block contexts.';
$string['cannotdeletebackupids'] = 'Couldn\'t delete previous backup ids';
$string['cannotdeletecategorycourse'] = 'Course \'{$a}\' failed to be deleted.';
$string['cannotdeletecategoryquestions'] = 'Could not delete questions from category \'{$a}\'';
$string['cannotdeletecourse'] = 'You do not have the permission to delete this course';
$string['cannotdeletecustomfield'] = 'Error deleting custom field data';
$string['cannotdeletedir'] = 'Cannot delete ({$a})';
@@ -664,3 +663,6 @@ $string['unknownhelp'] = 'Unknown help section {$a}';
// Deprecated since Moodle 4.5.
$string['cannotsetpassword'] = 'Could not set user password!';
$string['myisamproblem'] = 'Database tables are using MyISAM database engine, it is recommended to use ACID compliant engine with full transaction support such as InnoDB.';
// Deprecated since Moodle 5.0.
$string['cannotdeletecategoryquestions'] = 'Could not delete questions from category \'{$a}\'';
+3 -1
View File
@@ -131,7 +131,6 @@ $string['editthiscategory'] = 'Edit this category';
$string['emptyxml'] = 'Unknown error - empty imsmanifest.xml';
$string['enabled'] = 'Enabled';
$string['erroraccessingcontext'] = 'Cannot access context';
$string['errordeletingquestionsfromcategory'] = 'Error deleting questions from category {$a}.';
$string['errorduringpost'] = 'Error occurred during post-processing!';
$string['errorduringpre'] = 'Error occurred during pre-processing!';
$string['errorduringproc'] = 'Error occurred during processing!';
@@ -534,3 +533,6 @@ $string['version_selection'] = 'Version {$a->version}';
$string['versioninfo'] = 'Version {$a->version} (of {$a->latestversion})';
$string['versioninfolatest'] = 'Version {$a->version} (latest)';
$string['question_version'] = 'Question version';
// Deprecated since Moodle 5.0.
$string['errordeletingquestionsfromcategory'] = 'Error deleting questions from category {$a}.';
+5 -11
View File
@@ -51,17 +51,11 @@ abstract class question_base extends base {
*/
public function get_url() {
$cat = $this->other['categoryid'] . ',' . $this->contextid;
if ($this->courseid) {
if ($this->contextlevel == CONTEXT_MODULE) {
return new \moodle_url('/question/edit.php',
['cmid' => $this->contextinstanceid, 'cat' => $cat, 'lastchanged' => $this->objectid]);
}
return new \moodle_url('/question/edit.php',
['courseid' => $this->courseid, 'cat' => $cat, 'lastchanged' => $this->objectid]);
}
// Lets try viewing from the frontpage for contexts above course.
return new \moodle_url('/question/edit.php',
['courseid' => SITEID, 'edit' => $cat, 'lastchanged' => $this->objectid]);
return new \moodle_url(
'/question/edit.php',
['cmid' => $this->contextinstanceid, 'cat' => $cat, 'lastchanged' => $this->objectid]
);
}
/**
+2 -8
View File
@@ -51,14 +51,8 @@ abstract class question_category_base extends base {
*/
public function get_url() {
$cat = $this->objectid . ',' . $this->contextid;
if ($this->courseid) {
if ($this->contextlevel == CONTEXT_MODULE) {
return new \moodle_url('/question/edit.php', ['cmid' => $this->contextinstanceid, 'cat' => $cat]);
}
return new \moodle_url('/question/edit.php', ['courseid' => $this->courseid, 'cat' => $cat]);
}
// Lets try viewing from the frontpage for contexts above course.
return new \moodle_url('/question/edit.php', ['courseid' => SITEID, 'cat' => $cat, 'edit' => $this->objectid]);
return new \moodle_url('/question/edit.php', ['cmid' => $this->contextinstanceid, 'cat' => $cat]);
}
/**
+3 -10
View File
@@ -78,17 +78,10 @@ class question_moved extends question_base {
*/
public function get_url() {
$cat = $this->other['newcategoryid'] . ',' . $this->contextid;
if ($this->courseid) {
if ($this->contextlevel == CONTEXT_MODULE) {
return new \moodle_url('/question/edit.php',
['cmid' => $this->contextinstanceid, 'cat' => $cat, 'lastchanged' => $this->objectid]);
}
return new \moodle_url('/question/edit.php',
['courseid' => $this->courseid, 'cat' => $cat, 'lastchanged' => $this->objectid]);
}
// Lets try viewing from the frontpage for contexts above course.
return new \moodle_url('/question/edit.php',
['courseid' => SITEID, 'cat' => $cat, 'lastchanged' => $this->objectid]);
['cmid' => $this->contextinstanceid, 'cat' => $cat, 'lastchanged' => $this->objectid]
);
}
/**
+2 -8
View File
@@ -77,14 +77,8 @@ class questions_exported extends question_base {
*/
public function get_url() {
$cat = $this->other['categoryid'] . ',' . $this->contextid;
if ($this->courseid) {
if ($this->contextlevel == CONTEXT_MODULE) {
return new \moodle_url('/question/edit.php', ['cmid' => $this->contextinstanceid, 'cat' => $cat]);
}
return new \moodle_url('/question/edit.php', ['courseid' => $this->courseid, 'cat' => $cat]);
}
return new \moodle_url('/question/edit.php',
['courseid' => SITEID, 'cat' => $cat]);
return new \moodle_url('/question/edit.php', ['cmid' => $this->contextinstanceid, 'cat' => $cat]);
}
/**
+2 -8
View File
@@ -77,14 +77,8 @@ class questions_imported extends question_base {
*/
public function get_url() {
$cat = $this->other['categoryid'] . ',' . $this->contextid;
if ($this->courseid) {
if ($this->contextlevel == CONTEXT_MODULE) {
return new \moodle_url('/question/edit.php', ['cmid' => $this->contextinstanceid, 'cat' => $cat]);
}
return new \moodle_url('/question/edit.php', ['courseid' => $this->courseid, 'cat' => $cat]);
}
return new \moodle_url('/question/edit.php',
['courseid' => SITEID, 'cat' => $cat]);
return new \moodle_url('/question/edit.php', ['cmid' => $this->contextinstanceid, 'cat' => $cat]);
}
/**
-6
View File
@@ -4889,12 +4889,6 @@ function remove_course_contents($courseid, $showfeedback = true, ?array $options
echo $OUTPUT->notification($strdeleted.get_string('type_mod_plural', 'plugin'), 'notifysuccess');
}
// Delete questions and question categories.
question_delete_course($course);
if ($showfeedback) {
echo $OUTPUT->notification($strdeleted.get_string('questions', 'question'), 'notifysuccess');
}
// Delete content bank contents.
$cb = new \core_contentbank\contentbank();
$cbdeleted = $cb->delete_contents($coursecontext);
+54 -171
View File
@@ -438,57 +438,6 @@ function question_delete_context($contextid): array {
return [];
}
/**
* All question categories and their questions are deleted for this course.
*
* @param stdClass $course an object representing the activity
* @param bool $notused this argument is not used any more. Kept for backwards compatibility.
* @return bool always true.
*/
function question_delete_course($course, $notused = false): bool {
$coursecontext = context_course::instance($course->id);
question_delete_context($coursecontext->id);
return true;
}
/**
* Category is about to be deleted,
* 1/ All question categories and their questions are deleted for this course category.
* 2/ All questions are moved to new category
*
* @param stdClass|core_course_category $category course category object
* @param stdClass|core_course_category $newcategory empty means everything deleted, otherwise id of
* category where content moved
* @param bool $notused this argument is no longer used. Kept for backwards compatibility.
* @return boolean
*/
function question_delete_course_category($category, $newcategory, $notused=false): bool {
global $DB;
$context = context_coursecat::instance($category->id);
if (empty($newcategory)) {
question_delete_context($context->id);
} else {
// Move question categories to the new context.
if (!$newcontext = context_coursecat::instance($newcategory->id)) {
return false;
}
// Only move question categories if there is any question category at all!
if ($topcategory = question_get_top_category($context->id)) {
$newtopcategory = question_get_top_category($newcontext->id, true);
question_move_category_to_context($topcategory->id, $context->id, $newcontext->id);
$DB->set_field('question_categories', 'parent', $newtopcategory->id, ['parent' => $topcategory->id]);
// Now delete the top category.
$DB->delete_records('question_categories', ['id' => $topcategory->id]);
}
}
return true;
}
/**
* Creates a new category to save the questions in use.
*
@@ -502,6 +451,11 @@ function question_delete_course_category($category, $newcategory, $notused=false
function question_save_from_deletion($questionids, $newcontextid, $oldplace, $newcategory = null) {
global $DB;
$newcontext = context::instance_by_id($newcontextid);
if ($newcontext->contextlevel !== CONTEXT_MODULE) {
throw new moodle_exception("Invalid contextlevel: {$newcontext->contextlevel} for \$newcontextid {$newcontextid}");
}
// Make a category in the parent context to move the questions to.
if (is_null($newcategory)) {
$newcategory = new stdClass();
@@ -539,35 +493,17 @@ function question_delete_activity($cm, $notused = false): bool {
* This function will handle moving all tag instances to a new context for a
* given list of questions.
*
* Questions can be tagged in up to two contexts:
* 1.) The context the question exists in.
* 2.) The course context (if the question context is a higher context.
* E.g. course category context or system context.
*
* This means a question that exists in a higher context (e.g. course cat or
* system context) may have multiple groups of tags in any number of child
* course contexts.
*
* Questions in the course category context can be move "down" a context level
* into one of their child course contexts or activity contexts which affects the
* availability of that question in other courses / activities.
*
* In this case it makes the questions no longer available in the other course or
* activity contexts so we need to make sure that the tag instances in those other
* contexts are removed.
*
* @param stdClass[] $questions The list of question being moved (must include
* the id and contextid)
* @param context $newcontext The Moodle context the questions are being moved to
* @param context $newcontext The Moodle context the questions are being moved to, must be module context.
*/
function question_move_question_tags_to_new_context(array $questions, context $newcontext): void {
// If the questions are moving to a new course/activity context then we need to
// find any existing tag instances from any unavailable course contexts and
// delete them because they will no longer be applicable (we don't support
// tagging questions across courses).
$instancestodelete = [];
if ($newcontext->contextlevel !== CONTEXT_MODULE) {
debugging("Invalid contextlevel: {$newcontext->contextlevel}", DEBUG_DEVELOPER);
}
$instancesfornewcontext = [];
$newcontextparentids = $newcontext->get_parent_context_ids();
$questionids = array_map(function($question) {
return $question->id;
}, $questions);
@@ -580,7 +516,6 @@ function question_move_question_tags_to_new_context(array $questions, context $n
$tagid = $tagobject->taginstanceid;
$tagcontextid = $tagobject->taginstancecontextid;
$istaginnewcontext = $tagcontextid == $newcontext->id;
$istaginquestioncontext = $tagcontextid == $question->contextid;
if ($istaginnewcontext) {
// This tag instance is already in the correct context so we can
@@ -588,61 +523,10 @@ function question_move_question_tags_to_new_context(array $questions, context $n
continue;
}
if ($istaginquestioncontext) {
// This tag instance is in the question context so it needs to be
// updated.
$instancesfornewcontext[] = $tagid;
continue;
}
// These tag instances are in neither the new context nor the
// question context so we need to determine what to do based on
// the context they are in and the new question context.
$tagcontext = context::instance_by_id($tagcontextid);
$tagcoursecontext = $tagcontext->get_course_context(false);
// The tag is in a course context if get_course_context() returns
// itself.
$istaginstancecontextcourse = !empty($tagcoursecontext)
&& $tagcontext->id == $tagcoursecontext->id;
if ($istaginstancecontextcourse) {
// If the tag instance is in a course context we need to add some
// special handling.
$tagcontextparentids = $tagcontext->get_parent_context_ids();
$isnewcontextaparent = in_array($newcontext->id, $tagcontextparentids);
$isnewcontextachild = in_array($tagcontext->id, $newcontextparentids);
if ($isnewcontextaparent) {
// If the tag instance is a course context tag and the new
// context is still a parent context to the tag context then
// we can leave this tag where it is.
continue;
} else if ($isnewcontextachild) {
// If the new context is a child context (e.g. activity) of this
// tag instance then we should move all of this tag instance
// down into the activity context along with the question.
$instancesfornewcontext[] = $tagid;
} else {
// If the tag is in a course context that is no longer a parent
// or child of the new context then this tag instance should be
// removed.
$instancestodelete[] = $tagid;
}
} else {
// This is a catch all for any tag instances not in the question
// context or a course context. These tag instances should be
// updated to the new context id. This will clean up old invalid
// data.
$instancesfornewcontext[] = $tagid;
}
$instancesfornewcontext[] = $tagid;
}
}
if (!empty($instancestodelete)) {
// Delete any course context tags that may no longer be valid.
core_tag_tag::delete_instances_by_id($instancestodelete);
}
if (!empty($instancesfornewcontext)) {
// Update the tag instances to the new context id.
core_tag_tag::change_instances_context($instancesfornewcontext, $newcontext);
@@ -807,6 +691,11 @@ function move_question_set_references(int $oldcategoryid, int $newcatgoryid,
function question_move_category_to_context($categoryid, $oldcontextid, $newcontextid): void {
global $DB;
$newcontext = context::instance_by_id($newcontextid);
if ($newcontext->contextlevel !== CONTEXT_MODULE) {
debugging("Invalid contextlevel: {$newcontext->contextlevel}, must use CONTEXT_MODULE", DEBUG_DEVELOPER);
}
$questions = [];
$sql = "SELECT q.id, q.qtype
FROM {question} q
@@ -826,7 +715,6 @@ function question_move_category_to_context($categoryid, $oldcontextid, $newconte
];
}
$newcontext = context::instance_by_id($newcontextid);
question_move_question_tags_to_new_context($questions, $newcontext);
$subcatids = $DB->get_records_menu('question_categories', ['parent' => $categoryid], '', 'id,1');
@@ -935,9 +823,14 @@ function question_load_questions($questionids, $extrafields = '', $join = '') {
* @param object $question the question to tidy.
* @param stdClass $category The question_categories record for the given $question.
* @param \core_tag_tag[]|null $tagobjects The tags for the given $question.
* @param stdClass[]|null $filtercourses The courses to filter the course tags by.
* @param stdClass[]|null $filtercourses deprecated argument and should not be used
*/
function _tidy_question($question, $category, ?array $tagobjects = null, ?array $filtercourses = null): void {
if ($filtercourses !== null) {
debugging("Filtercourses is a deprecated argument in " . __FUNCTION__, DEBUG_DEVELOPER);
}
// Convert numeric fields to float. This prevents these being displayed as 1.0000000.
$question->defaultmark += 0;
$question->penalty += 0;
@@ -953,8 +846,6 @@ function _tidy_question($question, $category, ?array $tagobjects = null, ?array
if (!is_null($tagobjects)) {
$categorycontext = context::instance_by_id($category->contextid);
$sortedtagobjects = question_sort_tags($tagobjects, $categorycontext, $filtercourses);
$question->coursetagobjects = $sortedtagobjects->coursetagobjects;
$question->coursetags = $sortedtagobjects->coursetags;
$question->tagobjects = $sortedtagobjects->tagobjects;
$question->tags = $sortedtagobjects->tags;
}
@@ -978,12 +869,16 @@ function _tidy_question($question, $category, ?array $tagobjects = null, ?array
* @param mixed $questions Either an array of question objects to be updated
* or just a single question object
* @param bool $loadtags load the question tags from the tags table. Optional, default false.
* @param stdClass[] $filtercourses The courses to filter the course tags by.
* @param stdClass[] $filtercourses deprecated argument and should not be used
* @return bool Indicates success or failure.
*/
function get_question_options(&$questions, $loadtags = false, $filtercourses = null) {
global $DB;
if ($filtercourses !== null) {
debugging("Filtercourses is a deprecated argument in " . __FUNCTION__, DEBUG_DEVELOPER);
}
$questionlist = is_array($questions) ? $questions : [$questions];
$categoryids = [];
$questionids = [];
@@ -1037,55 +932,24 @@ function get_question_options(&$questions, $loadtags = false, $filtercourses = n
*
* @param \core_tag_tag[] $tagobjects The tags for the given $question.
* @param stdClass $categorycontext The question categories context.
* @param stdClass[]|null $filtercourses The courses to filter the course tags by.
* @param stdClass[]|null $filtercourses deprecated argument and should not be used.
* @return stdClass $sortedtagobjects Sorted tag objects.
*/
function question_sort_tags($tagobjects, $categorycontext, $filtercourses = null): stdClass {
// Questions can have two sets of tag instances. One set at the
// course context level and another at the context the question
// belongs to (e.g. course category, system etc).
if ($filtercourses !== null) {
debugging("Filtercourses is a deprecated argument in " . __FUNCTION__, DEBUG_DEVELOPER);
}
$sortedtagobjects = new stdClass();
$sortedtagobjects->coursetagobjects = [];
$sortedtagobjects->coursetags = [];
$sortedtagobjects->tagobjects = [];
$sortedtagobjects->tags = [];
$taginstanceidstonormalise = [];
$filtercoursecontextids = [];
$hasfiltercourses = !empty($filtercourses);
if ($hasfiltercourses) {
// If we're being asked to filter the course tags by a set of courses
// then get the context ids to filter below.
$filtercoursecontextids = array_map(function($course) {
$coursecontext = context_course::instance($course->id);
return $coursecontext->id;
}, $filtercourses);
}
foreach ($tagobjects as $tagobject) {
$tagcontextid = $tagobject->taginstancecontextid;
$tagcontext = context::instance_by_id($tagcontextid);
$tagcoursecontext = $tagcontext->get_course_context(false);
// This is a course tag if the tag context is a course context which
// doesn't match the question's context. Any tag in the question context
// is not considered a course tag, it belongs to the question.
$iscoursetag = $tagcoursecontext
&& $tagcontext->id == $tagcoursecontext->id
&& $tagcontext->id != $categorycontext->id;
if ($iscoursetag) {
// Any tag instance in a course context level is considered a course tag.
if (!$hasfiltercourses || in_array($tagcontextid, $filtercoursecontextids)) {
// Add the tag to the list of course tags if we aren't being
// asked to filter or if this tag is in the list of courses
// we're being asked to filter by.
$sortedtagobjects->coursetagobjects[] = $tagobject;
$sortedtagobjects->coursetags[$tagobject->id] = $tagobject->get_display_name();
}
} else {
// All non course context level tag instances or tags in the question
// context belong to the context that the question was created in.
// All tag instances belong to the context that the question was created in.
$sortedtagobjects->tagobjects[] = $tagobject;
$sortedtagobjects->tags[$tagobject->id] = $tagobject->get_display_name();
@@ -1100,7 +964,7 @@ function question_sort_tags($tagobjects, $categorycontext, $filtercourses = null
// happen below.
$tagobject->taginstancecontextid = $categorycontext->id;
}
}
}
if (!empty($taginstanceidstonormalise)) {
@@ -1232,6 +1096,15 @@ function question_get_top_category($contextid, $create = false) {
global $DB;
$category = $DB->get_record('question_categories', ['contextid' => $contextid, 'parent' => 0]);
$context = context::instance_by_id($contextid);
if ($context->contextlevel !== CONTEXT_MODULE) {
debugging(
"Invalid context level: {$context->contextlevel} for question_get_top_category, must be CONTEXT_MODULE",
DEBUG_DEVELOPER
);
return false;
}
if (!$category && $create) {
// We need to make one.
$category = new stdClass();
@@ -1485,6 +1358,15 @@ function question_edit_url($context) {
if (!has_any_capability(question_get_question_capabilities(), $context)) {
return false;
}
if ($context->contextlevel !== CONTEXT_MODULE) {
debugging(
"Invalid contextlevel: {$context->contextlevel} provided for question_edit_url, must be CONTEXT_MODULE",
DEBUG_DEVELOPER
);
return false;
}
$baseurl = $CFG->wwwroot . '/question/edit.php?';
$defaultcategory = question_get_default_category($context->id, true);
if ($defaultcategory) {
@@ -1503,6 +1385,7 @@ function question_edit_url($context) {
return $baseurl . 'cmid=' . $context->instanceid;
}
return $baseurl . 'cmid=' . $context->instanceid;
}
/**
@@ -79,7 +79,7 @@ Feature: Menu navigation has accurate checkmarks in topic course format
Given I log in as "admin"
And I am on "Course 1" course homepage
And I update the href of the "//*//a/following-sibling::*//a[contains(text(), 'Filters')]" "xpath" link to "#"
And I navigate to "Question bank" in current page administration
And I navigate to "Question banks" in current page administration
Then menu item "Filters" should not be active
@javascript
@@ -962,7 +962,7 @@ class secondary_test extends \advanced_testcase {
],
"Question bank should return nothing" => [
'/question/edit.php',
'courseid',
'cmid',
false
],
"Reports should return nothing" => [
File diff suppressed because it is too large Load Diff
+8 -20
View File
@@ -1836,6 +1836,13 @@ class structure {
* @throws coding_exception If the context level is unsupported.
*/
private function get_used_category_description(stdClass $qcategory, bool $includesubcategories): string {
$context = \context::instance_by_id($qcategory->contextid);
if ($context->contextlevel != CONTEXT_MODULE) {
throw new coding_exception('Unsupported context.');
}
if ($qcategory->name === 'top') { // This is a "top" question category.
if (!$includesubcategories) {
// Question categories labeled as "top" cannot directly contain questions. If the subcategories that may
@@ -1843,26 +1850,7 @@ class structure {
// that informs the user about the issues associated with these types of generated random questions.
return get_string('randomfaultynosubcat', 'mod_quiz');
}
$context = \context::instance_by_id($qcategory->contextid);
switch ($context->contextlevel) {
case CONTEXT_MODULE:
return get_string('randommodulewithsubcat', 'mod_quiz');
case CONTEXT_COURSE:
return get_string('randomcoursewithsubcat', 'mod_quiz');
case CONTEXT_COURSECAT:
$contextname = shorten_text($context->get_context_name(false), 100);
return get_string('randomcoursecatwithsubcat', 'mod_quiz', $contextname);
case CONTEXT_SYSTEM:
return get_string('randomsystemwithsubcat', 'mod_quiz');
default:
throw new coding_exception('Unsupported context.');
}
return get_string('randommodulewithsubcat', 'mod_quiz');
}
// Otherwise, return the description of the used standard question category, also indicating whether subcategories
// are included.
+1 -1
View File
@@ -50,7 +50,7 @@ require_once($CFG->dirroot . '/question/editlib.php');
$mdlscrollto = optional_param('mdlscrollto', '', PARAM_INT);
list($thispageurl, $contexts, $cmid, $cm, $quiz, $pagevars) =
question_edit_setup('editq', '/mod/quiz/edit.php', true);
question_edit_setup('editq', '/mod/quiz/edit.php');
$PAGE->set_url($thispageurl);
$PAGE->set_secondary_active_tab("mod_quiz_edit");
+1 -1
View File
@@ -37,7 +37,7 @@ require_once($CFG->dirroot . '/mod/quiz/locallib.php');
require_once($CFG->dirroot . '/question/editlib.php');
list($thispageurl, $contexts, $cmid, $cm, $quiz, $pagevars) =
question_edit_setup('editq', '/mod/quiz/editgrading.php', true);
question_edit_setup('editq', '/mod/quiz/editgrading.php');
$PAGE->set_url($thispageurl);
$PAGE->set_secondary_active_tab('mod_quiz_edit');
+3
View File
@@ -5,3 +5,6 @@ attemptsdeleted,mod_quiz
gradesdeleted,mod_quiz
useroverridesdeleted,mod_quiz
groupoverridesdeleted,mod_quiz
randomcoursecatwithsubcat,mod_quiz
randomcoursewithsubcat,mod_quiz
randomsystemwithsubcat,mod_quiz
+6 -3
View File
@@ -844,8 +844,7 @@ $string['quiztimer'] = 'Quiz Timer';
$string['quizwillopen'] = 'This quiz will open {$a}';
$string['random'] = 'Random question';
$string['randomcatwithsubcat'] = '{$a} and subcategories';
$string['randomcoursecatwithsubcat'] = 'Any category inside course category {$a}';
$string['randomcoursewithsubcat'] = 'Any category in this course';
$string['randomcreate'] = 'Create random questions';
$string['randomediting'] = 'Editing a random question';
$string['randomfaultynosubcat'] = 'Faulty question';
@@ -867,7 +866,6 @@ $string['randomquestiontags_help'] = 'You can restrict the selection criteria fu
The "random" questions will be selected from the questions that have all these tags.';
$string['randomquestionusinganewcategory'] = 'Random question using a new category';
$string['randomsystemwithsubcat'] = 'Any system-level category';
$string['randomwithsubcat'] = 'Questions from this category and its subcategories.';
$string['readytosend'] = 'You are about to send your whole quiz to be graded. Are you sure you want to continue?';
$string['reattemptquiz'] = 'Re-attempt quiz';
@@ -1141,3 +1139,8 @@ $string['attemptsdeleted'] = 'Quiz attempts deleted';
$string['gradesdeleted'] = 'Quiz grades deleted';
$string['useroverridesdeleted'] = 'User overrides deleted';
$string['groupoverridesdeleted'] = 'Group overrides deleted';
// Deprecated since Moodle 5.0.
$string['randomcoursecatwithsubcat'] = 'Any category inside course category {$a}';
$string['randomcoursewithsubcat'] = 'Any category in this course';
$string['randomsystemwithsubcat'] = 'Any system-level category';
@@ -20,12 +20,12 @@ Feature: Regrading quiz attempts using the Grades report
| student1 | C1 | student |
| student2 | C1 | student |
| student3 | C1 | student |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "activities" exist:
| activity | name | course | idnumber |
| quiz | Quiz for testing regrading | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name |
| Test questions | truefalse | TF |
+9 -8
View File
@@ -14,9 +14,16 @@ Feature: Attempt a quiz
And the following "course enrolments" exist:
| user | course | role |
| student | C1 | student |
And the following "activities" exist:
| activity | name | intro | course | idnumber | grade | navmethod |
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | 100 | free |
| quiz | Quiz 2 | Quiz 2 description | C1 | quiz2 | 6 | free |
| quiz | Quiz 3 | Quiz 3 description | C1 | quiz3 | 100 | free |
| quiz | Quiz 4 | Quiz 4 description | C1 | quiz4 | 100 | sequential |
| qbank | Qbank 1 | Question bank 1 | C1 | qbank1 | | |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | First question |
@@ -25,12 +32,6 @@ Feature: Attempt a quiz
| Test questions | truefalse | TF4 | Fourth question |
| Test questions | truefalse | TF5 | Fifth question |
| Test questions | truefalse | TF6 | Sixth question |
And the following "activities" exist:
| activity | name | intro | course | idnumber | grade | navmethod |
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | 100 | free |
| quiz | Quiz 2 | Quiz 2 description | C1 | quiz2 | 6 | free |
| quiz | Quiz 3 | Quiz 3 description | C1 | quiz3 | 100 | free |
| quiz | Quiz 4 | Quiz 4 description | C1 | quiz4 | 100 | sequential |
And quiz "Quiz 1" contains the following questions:
| question | page | maxmark |
| TF1 | 1 | |
+5 -2
View File
@@ -11,12 +11,15 @@ Feature: The various checks that may happen when an attept is started
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| qbank | Qbank 1 | Question bank 1 | C1 | qbank1 |
And the following "course enrolments" exist:
| user | course | role |
| student | C1 | student |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | qbank1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | Text of the first question |
@@ -14,12 +14,12 @@ Feature: Attempt a quiz with multiple grades
And the following "course enrolments" exist:
| user | course | role |
| student | C1 | student |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "activities" exist:
| activity | name | course |
| quiz | Quiz 1 | C1 |
| activity | name | course | idnumber |
| quiz | Quiz 1 | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
@javascript
Scenario: Navigation to, and display of, grading setup
@@ -12,13 +12,16 @@ Feature: Attempt a quiz where some questions require that the previous question
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| qbank | Qbank 1 | Question bank 1 | C1 | qbank1 |
And the following "course enrolments" exist:
| user | course | role |
| student | C1 | student |
| teacher | C1 | editingteacher |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | qbank1 | Test questions |
@javascript
Scenario Outline: A question that requires the previous one is initially blocked
@@ -16,9 +16,12 @@ Feature: Allow settings to show Max marks and Marks, Max marks only, or hide the
| user | course | role |
| teacher | C1 | editingteacher |
| student1 | C1 | student |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| qbank | Qbank 1 | Question bank 1 | C1 | qbank1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | qbank1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | First question |
@@ -14,18 +14,18 @@ Feature: Attempt a quiz in a sequential mode
| user | course | role |
| student | C1 | student |
| teacher | C1 | teacher |
And the following "activities" exist:
| activity | name | intro | course | idnumber | preferredbehaviour | navmethod |
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | immediatefeedback | sequential |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | First question |
| Test questions | truefalse | TF2 | Second question |
| Test questions | truefalse | TF3 | Third question |
| Test questions | truefalse | TF4 | Fourth question |
And the following "activities" exist:
| activity | name | intro | course | idnumber | preferredbehaviour | navmethod |
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | immediatefeedback | sequential |
And quiz "Quiz 1" contains the following questions:
| question | page | requireprevious |
| TF1 | 1 | 1 |
+4 -1
View File
@@ -155,7 +155,10 @@ class behat_mod_quiz extends behat_question_base {
return new moodle_url('/question/edit.php', [
'cmid' => $this->get_cm_by_quiz_name($identifier)->id,
]);
case 'question categories':
return new moodle_url('/question/bank/managecategories/category.php', [
'cmid' => $this->get_cm_by_quiz_name($identifier)->id,
]);
default:
throw new Exception('Unrecognised quiz page type "' . $type . '."');
@@ -16,15 +16,15 @@ Feature: Set a quiz to be marked complete when the student uses all attempts all
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
And the following "activities" exist:
| activity | name | course | idnumber | attempts | gradepass | completion | completionusegrade | completionpassgrade | completionattemptsexhausted |
| quiz | Test quiz name | C1 | quiz1 | 2 | 5.00 | 2 | 1 | 1 | 1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
And quiz "Test quiz name" contains the following questions:
| question | page |
| First question | 1 |
@@ -16,15 +16,15 @@ Feature: Manually complete a quiz
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
And the following "activities" exist:
| activity | name | course | idnumber | completion |
| quiz | Test quiz name | C1 | quiz1 | 1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
And quiz "Test quiz name" contains the following questions:
| question | page |
| First question | 1 |
+9 -20
View File
@@ -17,7 +17,9 @@ Feature: Edit quiz page - adding things
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| quiz | Quiz 1 | Quiz 1 for testing the Add menu | C1 | quiz1 |
| qbank | Qbank 1 | Question bank 1 for testing the Add menu | C1 | qbank1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And I am on the "Quiz 1" "mod_quiz > Edit" page logged in as "teacher1"
@javascript
@@ -100,21 +102,11 @@ Feature: Edit quiz page - adding things
in various categories and add them to the question bank.
# Create a couple of sub categories.
When I am on the "Course 1" "core_question > course question categories" page
Then I should see "Add category"
And I follow "Add category"
Then I set the field "Parent category" to "Default for Bank 1"
And I set the field "Name" to "Subcat 1"
And I set the field "Category info" to "This is sub category 1"
And I press "id_submitbutton"
And I should see "Subcat 1"
And I follow "Add category"
Then I set the field "Parent category" to "Default for C1"
And I set the field "Name" to "Subcat 2"
And I set the field "Category info" to "This is sub category 2"
And I press "id_submitbutton"
And I should see "Subcat 2"
Given the following "question categories" exist:
| contextlevel | reference | questioncategory | name |
| Activity module | quiz1 | Test questions | Subcat 1 |
| Activity module | quiz1 | Test questions | Subcat 2 |
When I am on the "Quiz 1" "mod_quiz > question categories" page
And I select "Questions" from the "Question bank tertiary navigation" singleselect
And I should see "Question bank"
@@ -240,10 +232,7 @@ Feature: Edit quiz page - adding things
@accessibility @javascript
Scenario: Check the accessibility of the quiz questions page
Given the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "questions" exist:
Given the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
| Test questions | truefalse | Other question | Answer the first question |
@@ -14,17 +14,17 @@ Feature: Edit quiz page - drag-and-drop
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | course | idnumber |
| quiz | Quiz 1 | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | Question A | This is question 01 |
| Test questions | truefalse | Question B | This is question 02 |
| Test questions | truefalse | Question C | This is question 03 |
And the following "activities" exist:
| activity | name | course | idnumber |
| quiz | Quiz 1 | C1 | quiz1 |
And quiz "Quiz 1" contains the following questions:
| question | page |
| Question A | 1 |
@@ -14,18 +14,18 @@ Feature: Setup multiple grades for a quiz
And the following "course enrolments" exist:
| user | course | role |
| teacher | C1 | editingteacher |
And the following "activities" exist:
| activity | name | course | idnumber |
| quiz | Quiz 1 | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | description | Info | Some information |
| Test questions | truefalse | Question A | This is question 01 |
| Test questions | truefalse | Question B | This is question 02 |
| Test questions | truefalse | Question C | This is question 03 |
And the following "activities" exist:
| activity | name | course |
| quiz | Quiz 1 | C1 |
@javascript
Scenario: Navigation to, and display of, grading setup
@@ -15,13 +15,14 @@ Feature: Editing question numbering of the existing questions already in a quiz
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| quiz | Quiz 1 | Quiz 1 for testing | C1 | quiz1 |
| quiz | Quiz 2 | Quiz 2 for testing | C1 | quiz2 |
| activity | name | intro | course | idnumber |
| quiz | Quiz 1 | Quiz 1 for testing | C1 | quiz1 |
| quiz | Quiz 2 | Quiz 2 for testing | C1 | quiz2 |
| qbank | Qbank 1 | Qbank for testing | C1 | qbank1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Questions Category 1|
| Course | C1 | Questions Category 2|
| contextlevel | reference | name |
| Activity module | qbank1 | Questions Category 1|
| Activity module | qbank1 | Questions Category 2|
Given the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Questions Category 1 | description | Description | This is decription ... |
@@ -14,12 +14,12 @@ Feature: Edit quiz page - remove multiple questions
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "activities" exist:
| activity | name | course | idnumber |
| quiz | Quiz 1 | C1 | quiz1 |
| activity | name | course | idnumber |
| quiz | Quiz 1 | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And I log in as "teacher1"
@javascript
@@ -14,12 +14,12 @@ Feature: Edit quiz page - remove questions
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "activities" exist:
| activity | name | course | idnumber |
| quiz | Quiz 1 | C1 | quiz1 |
| activity | name | course | idnumber |
| quiz | Quiz 1 | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And I log in as "teacher1"
@javascript
@@ -14,9 +14,12 @@ Feature: Edit quizzes where some questions require the previous one to have been
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | course | idnumber |
| qbank | Qbank 1 | C1 | qbank1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | qbank1 | Test questions |
And I log in as "teacher1"
@javascript
@@ -15,9 +15,12 @@ Feature: Edit quiz page - section headings
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | course | idnumber |
| qbank | Qbank 1 | C1 | qbank1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | qbank1 | Test questions |
And I log in as "teacher1"
@javascript
@@ -15,12 +15,12 @@ Feature: Edit quiz marks with no attempts
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | course | idnumber | grade | decimalpoints | questiondecimalpoints |
| quiz | Quiz 1 | C1 | quiz1 | 20 | 2 | -1 |
| activity | name | course | idnumber | grade | decimalpoints | questiondecimalpoints |
| quiz | Quiz 1 | C1 | quiz1 | 20 | 2 | -1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer me |
@@ -31,13 +31,6 @@ Feature: Switching question bank when adding questions to a quiz
| Activity module | qbank3 | Test questions 3 |
| Activity module | qbank4 | Test questions 4 |
| Activity module | quiz1 | Test questions 5 |
And the following "questions" exist:
| questioncategory | qtype | name | user | questiontext | idnumber |
| Test questions 1 | essay | question 01 name | admin | Question 01 text | qidnum1 |
| Test questions 2 | essay | question 02 name | teacher1 | Question 02 text | qidnum2 |
| Test questions 3 | essay | question 03 name | teacher1 | Question 03 text | qidnum3 |
| Test questions 4 | essay | question 04 name | admin | Question 04 text | qidnum4 |
| Test questions 5 | essay | question 05 name | teacher1 | Question 05 text | qidnum5 |
And I log in as "teacher1"
And I am on the "Quiz 1" "mod_quiz > Edit" page
@@ -16,15 +16,15 @@ Feature: Teachers see correct answers when overriding marks
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "activities" exist:
| activity | name | course | idnumber |
| quiz | Quiz 1 | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext | generalfeedback |
| Test questions | shortanswer | Kermit | What kind of animal is Kermit? | |
And the following "activities" exist:
| activity | name | course | idnumber |
| quiz | Quiz 1 | C1 | quiz1 |
And quiz "Quiz 1" contains the following questions:
| question | page |
| Kermit | 1 |
+9 -8
View File
@@ -16,14 +16,6 @@ Feature: Flag quiz questions
| user | course | role |
| student1 | C1 | student |
| teacher1 | C1 | teacher |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | First question |
| Test questions | truefalse | TF2 | Second question |
| Test questions | truefalse | TF3 | Third question |
And the following "activity" exists:
| activity | quiz |
| name | Quiz 1 |
@@ -36,6 +28,15 @@ Feature: Flag quiz questions
| generalfeedbackimmediately | 1 |
| rightanswerimmediately | 1 |
| overallfeedbackimmediately | 1 |
| idnumber | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | First question |
| Test questions | truefalse | TF2 | Second question |
| Test questions | truefalse | TF3 | Third question |
And quiz "Quiz 1" contains the following questions:
| question | page |
| TF1 | 1 |
+3 -2
View File
@@ -42,9 +42,10 @@ Feature: Viewing results by group
| activity | name | intro | course | idnumber | groupmode |
| quiz | Separate quiz | quiz with separate groups | C1 | quiz1 | 1 |
| quiz | Visible quiz | quiz with visible groups | C1 | quiz2 | 2 |
| qbank | Qbank 1 | | C1 | qbank1 | |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | qbank1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | First question |
+5 -2
View File
@@ -14,9 +14,12 @@ Feature: Display of information before starting a quiz
And the following "course enrolments" exist:
| user | course | role |
| student | C1 | student |
And the following "activities" exist:
| activity | name | course | idnumber |
| qbank | Qbank 1 | C1 | qbank1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | qbank1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | Text of the first question |
@@ -16,15 +16,16 @@ Feature: Teachers can override the grade for any question
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "activities" exist:
| activity | name | intro | course | idnumber | grade |
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | 20 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext | defaultmark |
| Test questions | essay | TF1 | First question | 20 |
And the following "activities" exist:
| activity | name | intro | course | idnumber | grade |
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | 20 |
And quiz "Quiz 1" contains the following questions:
| question | page |
| TF1 | 1 |
+5 -5
View File
@@ -14,12 +14,12 @@ Feature: Preview a quiz as a teacher
And the following "course enrolments" exist:
| user | course | role |
| teacher | C1 | editingteacher |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 |
| activity | name | intro | course | idnumber |
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | First question |
@@ -16,9 +16,12 @@ Feature: Quiz availability can be set
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "activities" exist:
| activity | name | course | idnumber |
| qbank | Qbank 1 | C1 | qbank1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | qbank1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | First question |
@@ -16,17 +16,17 @@ Feature: Set a quiz with certainty-based marking
| user | course | role |
| student1 | C1 | student |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | course | idnumber |
| quiz | Quiz 1 | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | First question |
| Test questions | truefalse | TF2 | Second question |
| Test questions | truefalse | TF3 | Third question |
And the following "activities" exist:
| activity | name | course |
| quiz | Quiz 1 | C1 |
And quiz "Quiz 1" contains the following questions:
| question | page |
| TF1 | 1 |
@@ -16,12 +16,6 @@ Feature: View activity completion in the quiz activity
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
And the following "activity" exists:
| activity | quiz |
| course | C1 |
@@ -37,6 +31,12 @@ Feature: View activity completion in the quiz activity
| completionattemptsexhausted | 1 |
| completionminattemptsenabled | 1 |
| completionminattempts | 1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
And quiz "Test quiz name" contains the following questions:
| question | page |
| First question | 1 |
@@ -17,12 +17,6 @@ Feature: Ensure saving a quiz does not modify the completion settings.
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
And the following "activity" exists:
| activity | quiz |
| course | C1 |
@@ -36,6 +30,12 @@ Feature: Ensure saving a quiz does not modify the completion settings.
| completionusegrade | 1 |
| completionpassgrade | 1 |
| completionattemptsexhausted | 1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
And quiz "Test quiz" contains the following questions:
| question | page |
| First question | 1 |
@@ -16,13 +16,6 @@ Feature: Activity completion in the quiz activity with unlocked and re-grading.
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext | defaultmark |
| Test questions | truefalse | First question | Answer the first question | 8 |
| Test questions | truefalse | Second question | Answer the second question | 2 |
And the following "activity" exists:
| activity | quiz |
| course | C1 |
@@ -35,6 +28,13 @@ Feature: Activity completion in the quiz activity with unlocked and re-grading.
| completion | 2 |
| completionusegrade | 1 |
| completionpassgrade | 1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext | defaultmark |
| Test questions | truefalse | First question | Answer the first question | 8 |
| Test questions | truefalse | Second question | Answer the second question | 2 |
And quiz "Test quiz name" contains the following questions:
| question | page |
| First question | 1 |
+5 -2
View File
@@ -15,9 +15,12 @@ Feature: Enable deferred or immediate feedback for quiz
| user | course | role |
| student1 | C1 | student |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | course | idnumber |
| qbank | Qbank 1 | C1 | qbank1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | qbank1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | First question |
@@ -16,16 +16,16 @@ Feature: Set a quiz to be interactive with multiple tries
| user | course | role |
| student1 | C1 | student |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | course | preferredbehaviour | specificfeedbackduring | idnumber |
| quiz | Quiz 1 | C1 | interactive | 1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext | template | hint1 | hint2 | shuffleanswers |
| Test questions | multichoice | MC1 | First question | one_of_four | Hint 1 | Hint 2 | 0 |
| Test questions | multichoice | MC2 | Second question | one_of_four | Hint 1 | Hint 2 | 0 |
And the following "activities" exist:
| activity | name | course | preferredbehaviour | specificfeedbackduring |
| quiz | Quiz 1 | C1 | interactive | 1 |
And quiz "Quiz 1" contains the following questions:
| question | page |
| MC1 | 1 |
@@ -14,12 +14,12 @@ Feature: Quiz question versioning
And the following "course enrolments" exist:
| user | course | role |
| teacher | C1 | editingteacher |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "activities" exist:
| activity | name | course | idnumber |
| quiz | Quiz 1 | C1 | quiz1 |
| activity | name | course | idnumber |
| quiz | Quiz 1 | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
+6 -6
View File
@@ -20,15 +20,15 @@ Feature: Quiz reset
| name | course | idnumber |
| Group 1 | C1 | G1 |
| Group 2 | C1 | G2 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | First question |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| quiz | Test quiz name | Test quiz description | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | First question |
And quiz "Test quiz name" contains the following questions:
| question | page |
| TF1 | 1 |
+22 -13
View File
@@ -16,14 +16,15 @@ Feature: Moving a question to another category should not affect random question
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| quiz | Quiz 1 | Quiz 1 for testing the Add random question form | C1 | quiz1 |
| activity | name | intro | course | idnumber |
| quiz | Quiz 1 | Quiz 1 for testing the Add random question form | C1 | quiz1 |
| qbank | Qbank 1 | Question bank 1 | C1 | qbank1 |
And the following "question categories" exist:
| contextlevel | reference | questioncategory | name |
| Course | C1 | Top | top |
| Course | C1 | top | Default for C1 |
| Course | C1 | Default for C1 | Subcategory |
| Course | C1 | top | Used category |
| contextlevel | reference | questioncategory | name |
| Activity module | qbank1 | Top | top |
| Activity module | qbank1 | top | Default for Qbank 1 |
| Activity module | qbank1 | Default for Qbank 1 | Subcategory |
| Activity module | qbank1 | top | Used category |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Used category | essay | Test question to be moved | Write about whatever you want |
@@ -33,21 +34,27 @@ Feature: Moving a question to another category should not affect random question
Given I am on the "Quiz 1" "mod_quiz > Edit" page logged in as "teacher1"
When I open the "last" add to quiz menu
And I follow "a random question"
And I click on "Switch bank" "button"
And I click on "Qbank 1" "link" in the "Select question bank" "dialogue"
And I apply question bank filter "Category" with value "Used category"
And I press "Add random question"
And I should see "Random (Used category) based on filter condition" on quiz page "1"
And I click on "Configure question" "link" in the "Random (Used category) based on filter condition" "list_item"
And I should see "Used category"
And I am on "Course 1" course homepage
And I navigate to "Question bank" in current page administration
And I navigate to "Question banks" in current page administration
And I click on "Qbank 1" "link"
And I apply question bank filter "Category" with value "Used category"
And I click on "Test question to be moved" "checkbox" in the "Test question to be moved" "table_row"
And I click on "With selected" "button"
And I click on question bulk action "move"
And I set the field "Question category" to "Subcategory"
And I press "Move to"
Then I should see "Test question to be moved"
And I should see "Subcategory (1)"
And I open the autocomplete suggestions list in the ".search-categories" "css_element"
And I click on "Subcategory" item in the autocomplete list
And I click on "Move questions" "button"
And I should see "Are you sure you want to move these questions?"
And I click on "Confirm" "button"
And I wait until the page is ready
Then I should see "Subcategory (1)"
And I am on the "Quiz 1" "mod_quiz > Edit" page
And I should see "Random (Used category) based on filter condition" on quiz page "1"
And I click on "Configure question" "link" in the "Random (Used category) based on filter condition" "list_item"
@@ -58,10 +65,12 @@ Feature: Moving a question to another category should not affect random question
Given I am on the "Quiz 1" "mod_quiz > Edit" page logged in as "teacher1"
When I open the "last" add to quiz menu
And I follow "a random question"
Then I click on "Switch bank" "button"
And I click on "Qbank 1" "link" in the "Select question bank" "dialogue"
And I apply question bank filter "Category" with value "Used category"
And I press "Add random question"
And I should see "Random (Used category) based on filter condition" on quiz page "1"
And I am on the "Course 1" "core_question > course question categories" page
And I am on the "Qbank 1" "core_question > question categories" page
And I open the action menu in "Used category" "list_item"
And I choose "Edit" in the open action menu
And I set the following fields to these values:
+5 -5
View File
@@ -18,16 +18,16 @@ Feature: Several attempts in a quiz
| student1 | C1 | student |
| student2 | C1 | student |
| teacher | C1 | teacher |
And the following "activities" exist:
| activity | name | intro | course | idnumber | preferredbehaviour | navmethod |
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | immediatefeedback | free |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | First question |
| Test questions | truefalse | TF2 | Second question |
And the following "activities" exist:
| activity | name | intro | course | idnumber | preferredbehaviour | navmethod |
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | immediatefeedback | free |
And quiz "Quiz 1" contains the following questions:
| question | page | requireprevious |
| TF1 | 1 | 1 |
@@ -125,11 +125,12 @@ Feature: Settings form fields disabled if not required
@javascript
Scenario: If there are quiz attempts, there is not option to repaginate.
Given the following "activities" exist:
| activity | name | intro | course | idnumber |
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 |
| activity | name | intro | course | idnumber |
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 |
| qbank | Qbank 1 | Qbank for testing | C1 | qbank1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | qbank1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | First question |
@@ -151,19 +151,20 @@ class quiz_question_restore_test extends \advanced_testcase {
}
/**
* Test if a duplicate does not duplicate questions in course question bank.
* Test if a duplicate does not duplicate questions from a shared question bank.
*
* @covers ::duplicate_module
*/
public function test_quiz_duplicate_does_not_duplicate_course_question_bank_questions(): void {
public function test_quiz_duplicate_does_not_duplicate_questions_from_shared_banks(): void {
$this->resetAfterTest();
$quiz = $this->create_test_quiz($this->course);
// Test for questions from a different context.
$context = \context_course::instance($this->course->id);
$qbank = self::getDataGenerator()->create_module('qbank', ['course' => $this->course->id]);
// Test for questions from a qbank context.
$context = \context_module::instance($qbank->cmid);
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$this->add_two_regular_questions($questiongenerator, $quiz, ['contextid' => $context->id]);
$this->add_one_random_question($questiongenerator, $quiz, ['contextid' => $context->id]);
// Count the questions in course context.
// Count the questions in qbank context.
$this->assertEquals(7, $this->question_count($context->id));
$newquiz = $this->duplicate_quiz($this->course, $quiz);
$this->assertEquals(7, $this->question_count($context->id));
@@ -184,7 +184,7 @@ class column_manager extends column_manager_base {
$contexts,
new moodle_url('/question/bank/columnsortorder/sortcolumns.php'),
$course,
null,
$cm,
$params
);
return $questionbank;
@@ -137,7 +137,7 @@ Feature: Set question bank column order and size
And I click on "Disable" "link" in the "Question statistics" "table_row"
And I click on "Enable" "link" in the "Question statistics" "table_row"
And I click on "Disable" "link" in the "Question statistics" "table_row"
And I am on the "Course 1" "core_question > course question bank" page
And I am on the "Test quiz Q001" "mod_quiz > question bank" page
Then I should see "Question bank"
And "Create a new question" "button" should exist
# Really, we are just checking the question bank displayed without errors.
@@ -48,10 +48,12 @@ class column_manager_test extends advanced_testcase {
protected static function get_question_bank(): view {
$course = self::getDataGenerator()->create_course();
$qbank = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
$cm = get_coursemodule_from_id('qbank', $qbank->cmid);
$questionbank = new view(
new question_edit_contexts(\context_module::instance($qbank->cmid)),
new moodle_url('/'),
$course
$course,
$cm
);
return $questionbank;
}
+2 -1
View File
@@ -74,7 +74,8 @@ class backup_test extends \advanced_testcase {
// Question initial set up.
$this->category = $this->getDataGenerator()->create_category();
$this->course = $this->getDataGenerator()->create_course(['category' => $this->category->id]);
$context = \context_coursecat::instance($this->category->id);
$qbank = self::getDataGenerator()->create_module('qbank', ['course' => $this->course->id]);
$context = \context_module::instance($qbank->cmid);
$this->qgen = $this->getDataGenerator()->get_plugin_generator('core_question');
$qcat = $this->qgen->create_question_category(['contextid' => $context->id]);
@@ -17,8 +17,8 @@ Feature: A Teacher can comment in a question
| activity | name | course | idnumber |
| quiz | Test quiz | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
@@ -10,8 +10,8 @@ Feature: Use the qbank plugin manager page for comment
| activity | name | course | idnumber |
| quiz | Test quiz | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
+4 -2
View File
@@ -84,7 +84,8 @@ class lib_test extends \advanced_testcase {
$category = $this->getDataGenerator()->create_category();
$course = $this->getDataGenerator()->create_course(['category' => $category->id]);
$qgen = $this->getDataGenerator()->get_plugin_generator('core_question');
$context = \context_coursecat::instance($category->id);
$qbank = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
$context = \context_module::instance($qbank->cmid);
$qcat = $qgen->create_question_category(['contextid' => $context->id]);
$question = $qgen->create_question('shortanswer', null, ['category' => $qcat->id, 'idnumber' => 'q1']);
@@ -111,8 +112,9 @@ class lib_test extends \advanced_testcase {
// Make a test question.
$category = $this->getDataGenerator()->create_category();
$course = $this->getDataGenerator()->create_course(['category' => $category->id]);
$qbank = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
$context = \context_module::instance($qbank->cmid);
$qgen = $this->getDataGenerator()->get_plugin_generator('core_question');
$context = \context_coursecat::instance($category->id);
$qcat = $qgen->create_question_category(['contextid' => $context->id]);
$question = $qgen->create_question('shortanswer', null, ['category' => $qcat->id, 'idnumber' => 'q1']);
$args = [
@@ -91,7 +91,8 @@ class customfield_test extends \advanced_testcase {
// Question initial set up.
$this->category = $this->getDataGenerator()->create_category();
$this->course = $this->getDataGenerator()->create_course(['category' => $this->category->id]);
$context = \context_coursecat::instance($this->category->id);
$qbank = self::getDataGenerator()->create_module('qbank', ['course' => $this->course->id]);
$context = \context_module::instance($qbank->cmid);
$this->qgen = $this->getDataGenerator()->get_plugin_generator('core_question');
$qcat = $this->qgen->create_question_category(['contextid' => $context->id]);
@@ -33,9 +33,10 @@ class question_handler_test extends \advanced_testcase {
* @throws coding_exception
*/
protected function setup_question(): int {
$category = $this->getDataGenerator()->create_category();
$course = self::getDataGenerator()->create_course();
$qbank = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$context = \context_coursecat::instance($category->id);
$context = \context_module::instance($qbank->cmid);
$questioncategory = $questiongenerator->create_question_category(['contextid' => $context->id]);
$questiondata = ['category' => $questioncategory->id, 'idnumber' => 'q1'];
$question = $questiongenerator->create_question('shortanswer', null, $questiondata);
@@ -64,12 +64,8 @@ class delete_action extends question_action_base {
$this->strdelete = get_string('delete');
$this->strrestore = get_string('restore');
$this->deletequestionurl = new \moodle_url('/question/bank/deletequestion/delete.php');
if (!empty($this->qbank->cm->id)) {
$this->returnparams['cmid'] = $this->qbank->cm->id;
}
if (!empty($this->qbank->course->id)) {
$this->returnparams['courseid'] = $this->qbank->course->id;
}
$this->returnparams['cmid'] = $this->qbank->cm->id;
if (!empty($this->qbank->returnurl)) {
$this->returnparams['returnurl'] = $this->qbank->returnurl;
}
+4 -13
View File
@@ -31,8 +31,7 @@ global $DB, $OUTPUT, $PAGE, $COURSE;
$deleteselected = optional_param('deleteselected', false, PARAM_BOOL);
$returnurl = optional_param('returnurl', 0, PARAM_LOCALURL);
$cmid = optional_param('cmid', 0, PARAM_INT);
$courseid = optional_param('courseid', 0, PARAM_INT);
$cmid = required_param('cmid', PARAM_INT);
$deleteall = optional_param('deleteall', false, PARAM_BOOL);
if ($returnurl) {
@@ -41,16 +40,9 @@ if ($returnurl) {
\core_question\local\bank\helper::require_plugin_enabled('qbank_deletequestion');
if ($cmid) {
list($module, $cm) = get_module_from_cmid($cmid);
require_login($cm->course, false, $cm);
$thiscontext = context_module::instance($cmid);
} else if ($courseid) {
require_login($courseid, false);
$thiscontext = context_course::instance($courseid);
} else {
throw new moodle_exception('missingcourseorcmid', 'question');
}
[$module, $cm] = get_module_from_cmid($cmid);
require_login($cm->course, false, $cm);
$thiscontext = context_module::instance($cmid);
$contexts = new core_question\local\bank\question_edit_contexts($thiscontext);
$url = new moodle_url('/question/bank/deletequestion/delete.php');
@@ -115,7 +107,6 @@ if ($deleteselected) {
'sesskey' => sesskey(),
'returnurl' => $returnurl->out_as_local_url(false),
'cmid' => $cmid,
'courseid' => $courseid,
],
);
$continue = new \single_button($deleteurl, get_string('delete'), 'post');
@@ -10,8 +10,8 @@ Feature: Use the qbank plugin manager page for deletequestion
| activity | name | course | idnumber |
| quiz | Test quiz | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
@@ -58,6 +58,7 @@ Feature: Use the qbank plugin manager page for deletequestion
@javascript
Scenario: I should be able to delete a question when filtered using tags
Given I am on the "First question" "core_question > edit" page logged in as "admin"
And I change window size to "large"
And I set the following fields to these values:
| Tags | foo |
And I click on "Save changes" "button"
+8 -21
View File
@@ -29,8 +29,7 @@ use qbank_editquestion\editquestion_helper;
// Read URL parameters.
$categoryid = required_param('category', PARAM_INT);
$cmid = optional_param('cmid', 0, PARAM_INT);
$courseid = optional_param('courseid', 0, PARAM_INT);
$cmid = required_param('cmid', PARAM_INT);
$returnurl = optional_param('returnurl', 0, PARAM_LOCALURL);
$appendqnumstring = optional_param('appendqnumstring', '', PARAM_ALPHA);
$validationerror = optional_param('validationerror', false, PARAM_BOOL);
@@ -45,20 +44,10 @@ if (!$category = $DB->get_record('question_categories', array('id' => $categoryi
throw new moodle_exception('categorydoesnotexist', 'question', $returnurl);
}
if ($cmid) {
list($module, $cm) = get_module_from_cmid($cmid);
require_login($cm->course, false, $cm);
$thiscontext = context_module::instance($cmid);
$hiddenparams['cmid'] = $cmid;
} else if ($courseid) {
require_login($courseid, false);
$thiscontext = context_course::instance($courseid);
$module = null;
$cm = null;
$hiddenparams['courseid'] = $courseid;
} else {
throw new moodle_exception('missingcourseorcmid', 'question');
}
list($module, $cm) = get_module_from_cmid($cmid);
require_login($cm->course, false, $cm);
$thiscontext = context_module::instance($cmid);
$hiddenparams['cmid'] = $cmid;
// Check permissions.
$categorycontext = context::instance_by_id($category->contextid);
@@ -73,11 +62,9 @@ if (!empty($appendqnumstring)) {
}
$PAGE->set_url('/question/bank/editquestion/addquestion.php', $hiddenparams);
if ($cmid) {
$questionbankurl = new moodle_url('/question/edit.php', array('cmid' => $cmid));
} else {
$questionbankurl = new moodle_url('/question/edit.php', array('courseid' => $courseid));
}
$questionbankurl = new moodle_url('/question/edit.php', ['cmid' => $cmid]);
navigation_node::override_active_url($questionbankurl);
$chooseqtype = get_string('chooseqtypetoadd', 'question');
@@ -50,11 +50,7 @@ class copy_action extends question_action_base {
$this->strcopy = get_string('duplicate');
$this->duplicatequestionurl = new \moodle_url('/question/bank/editquestion/question.php',
array('returnurl' => $this->qbank->returnurl));
if ($this->qbank->cm !== null) {
$this->duplicatequestionurl->param('cmid', $this->qbank->cm->id);
} else {
$this->duplicatequestionurl->param('courseid', $this->qbank->course->id);
}
$this->duplicatequestionurl->param('cmid', $this->qbank->cm->id);
}
public function get_menu_position(): int {
@@ -60,11 +60,7 @@ class edit_action extends question_action_base {
$this->strview = get_string('view');
$this->editquestionurl = new \moodle_url('/question/bank/editquestion/question.php',
array('returnurl' => $this->qbank->returnurl));
if ($this->qbank->cm !== null) {
$this->editquestionurl->param('cmid', $this->qbank->cm->id);
} else {
$this->editquestionurl->param('courseid', $this->qbank->course->id);
}
$this->editquestionurl->param('cmid', $this->qbank->cm->id);
}
public function get_menu_position(): int {
+8 -26
View File
@@ -31,8 +31,7 @@ $id = optional_param('id', 0, PARAM_INT); // Question id.
$makecopy = optional_param('makecopy', 0, PARAM_BOOL);
$qtype = optional_param('qtype', '', PARAM_COMPONENT);
$categoryid = optional_param('category', 0, PARAM_INT);
$cmid = optional_param('cmid', 0, PARAM_INT);
$courseid = optional_param('courseid', 0, PARAM_INT);
$cmid = required_param('cmid', PARAM_INT);
$wizardnow = optional_param('wizardnow', '', PARAM_ALPHA);
$originalreturnurl = optional_param('returnurl', 0, PARAM_LOCALURL);
$appendqnumstring = optional_param('appendqnumstring', '', PARAM_ALPHA);
@@ -57,9 +56,6 @@ if ($categoryid !== 0) {
if ($cmid !== 0) {
$url->param('cmid', $cmid);
}
if ($courseid !== 0) {
$url->param('courseid', $courseid);
}
if ($wizardnow !== '') {
$url->param('wizardnow', $wizardnow);
}
@@ -77,11 +73,8 @@ if ($mdlscrollto) {
}
$PAGE->set_url($url);
if ($cmid) {
$questionbankurl = new moodle_url('/question/edit.php', array('cmid' => $cmid));
} else {
$questionbankurl = new moodle_url('/question/edit.php', array('courseid' => $courseid));
}
$questionbankurl = new moodle_url('/question/edit.php', ['cmid' => $cmid]);
navigation_node::override_active_url($questionbankurl);
if ($originalreturnurl) {
@@ -96,18 +89,10 @@ if ($mdlscrollto) {
$returnurl->param('mdlscrollto', $mdlscrollto);
}
if ($cmid) {
list($module, $cm) = get_module_from_cmid($cmid);
require_login($cm->course, false, $cm);
$thiscontext = context_module::instance($cmid);
} else if ($courseid) {
require_login($courseid, false);
$thiscontext = context_course::instance($courseid);
$module = null;
$cm = null;
} else {
throw new moodle_exception('missingcourseorcmid', 'question');
}
list($module, $cm) = get_module_from_cmid($cmid);
require_login($cm->course, false, $cm);
$thiscontext = context_module::instance($cmid);
$contexts = new core_question\local\bank\question_edit_contexts($thiscontext);
$PAGE->set_pagelayout('admin');
@@ -119,10 +104,7 @@ if ($id) {
if (!$question = $DB->get_record('question', array('id' => $id))) {
throw new moodle_exception('questiondoesnotexist', 'question', $returnurl);
}
// We can use $COURSE here because it's been initialised as part of the
// require_login above. Passing it as the third parameter tells the function
// to filter the course tags by that course.
get_question_options($question, true, [$COURSE]);
get_question_options($question, true);
} else if ($categoryid && $qtype) { // Only for creating new questions.
$question = new stdClass();
@@ -10,8 +10,8 @@ Feature: Use the qbank plugin manager page for editquestion
| activity | name | course | idnumber |
| quiz | Test quiz | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
@@ -10,8 +10,8 @@ Feature: Use the qbank base view to test the status change using
| activity | name | course | idnumber |
| quiz | Test quiz | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
+3 -15
View File
@@ -35,22 +35,10 @@ class helper {
* @return \moodle_url the requested URL.
*/
public static function question_get_export_single_question_url($question): \moodle_url {
$params = ['id' => $question->id, 'sesskey' => sesskey()];
$context = \context::instance_by_id($question->contextid);
switch ($context->contextlevel) {
case CONTEXT_MODULE:
$params['cmid'] = $context->instanceid;
break;
case CONTEXT_COURSE:
$params['courseid'] = $context->instanceid;
break;
default:
$params['courseid'] = SITEID;
}
return new \moodle_url('/question/bank/exporttoxml/exportone.php', $params);
return new \moodle_url('/question/bank/exporttoxml/exportone.php',
['id' => $question->id, 'sesskey' => sesskey(), 'cmid' => $context->instanceid]
);
}
}
+6 -14
View File
@@ -29,24 +29,16 @@ require_once($CFG->dirroot . '/question/format/xml/format.php');
// Get the parameters from the URL.
$questionid = required_param('id', PARAM_INT);
$cmid = optional_param('cmid', 0, PARAM_INT);
$courseid = optional_param('courseid', 0, PARAM_INT);
$cmid = required_param('cmid', PARAM_INT);
$urlparams = ['id' => $questionid, 'sesskey' => sesskey()];
\core_question\local\bank\helper::require_plugin_enabled('qbank_exporttoxml');
if ($cmid) {
$cm = get_coursemodule_from_id(null, $cmid);
require_login($cm->course, false, $cm);
$thiscontext = context_module::instance($cmid);
$urlparams['cmid'] = $cmid;
} else if ($courseid) {
require_login($courseid, false);
$thiscontext = context_course::instance($courseid);
$urlparams['courseid'] = $courseid;
} else {
throw new moodle_exception('missingcourseorcmid', 'question');
}
$cm = get_coursemodule_from_id(null, $cmid);
require_login($cm->course, false, $cm);
$thiscontext = context_module::instance($cmid);
$urlparams['cmid'] = $cmid;
require_sesskey();
// Load the necessary data.
@@ -10,8 +10,8 @@ Feature: Use the qbank plugin manager page for exporttoxml
| activity | name | course | idnumber |
| quiz | Test quiz | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
@@ -14,9 +14,12 @@ Feature: A teacher can export a question as XML from the preview question screen
And the following "course enrolments" exist:
| user | course | role |
| teacher | C1 | editingteacher |
And the following "activities" exist:
| activity | name | course | idnumber |
| qbank | Qbank 1 | C1 | qbank1 |
And the following "question categories" exist:
| name | contextlevel | reference |
| Test questions | Course | C1 |
| contextlevel | reference | name |
| Activity module | qbank1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name |
| Test questions | numerical | Test question to be previewed |
+27
View File
@@ -34,8 +34,12 @@ class helper {
* @param int $courseid id of the course
* @param ?string $filter filter param to pass to the History view
* @return \moodle_url
* @deprecated since Moodle 5.0.
* @todo MDL-82413 Final deprecation in Moodle 6.0.
*/
#[\core\attribute\deprecated(replacement: 'qbank_history\helper::get_question_history_url', since: '5.0', mdl: 'MDL-71378')]
public static function question_history_url(int $entryid, string $returnrul, int $courseid, ?string $filter): \moodle_url {
\core\deprecation::emit_deprecation_if_present([self::class, __FUNCTION__]);
$params = [
'entryid' => $entryid,
'returnurl' => $returnrul,
@@ -48,4 +52,27 @@ class helper {
return new \moodle_url('/question/bank/history/history.php', $params);
}
/**
* Get the question history url.
*
* @param int $entryid id of the question entry
* @param string $returnrul url of the page to return to
* @param int $cmid id of the coursemodule holding the question bank.
* @param ?string $filter filter param to pass to the History view
* @return \moodle_url
*/
public static function get_question_history_url(int $entryid, string $returnrul, int $cmid, ?string $filter) {
$params = [
'entryid' => $entryid,
'returnurl' => $returnrul,
'cmid' => $cmid,
];
if (!is_null($filter)) {
$params['filter'] = $filter;
}
return new \moodle_url('/question/bank/history/history.php', $params);
}
}
@@ -49,10 +49,10 @@ class history_action extends question_action_base {
}
if (question_has_capability_on($question, 'use')) {
$url = helper::question_history_url(
$url = helper::get_question_history_url(
$question->questionbankentryid,
$this->qbank->returnurl,
$this->qbank->course->id,
$this->qbank->cm->id,
$this->qbank->base_url()->param('filter'),
);
return [$url, 't/log', $this->strpreview];
@@ -63,6 +63,10 @@ class question_history_view extends view {
array $params = [],
array $extraparams = [],
) {
if ($cm === null) {
debugging('$cm is now a required field', DEBUG_DEVELOPER);
}
$this->entryid = $extraparams['entryid'];
$this->basereturnurl = new \moodle_url($extraparams['returnurl']);
parent::__construct($contexts, $pageurl, $course, $cm, $params, $extraparams);
+1 -1
View File
@@ -42,7 +42,7 @@ $PAGE->set_url($url);
// Additional param to differentiate with other question bank view.
$extraparams['entryid'] = $entryid;
$extraparams['returnurl'] = $returnurl;
$questionbank = new \qbank_history\question_history_view($contexts, $url, $COURSE, null, $pagevars, $extraparams);
$questionbank = new \qbank_history\question_history_view($contexts, $url, $COURSE, $cm, $pagevars, $extraparams);
$streditingquestions = get_string('history_header', 'qbank_history');
$PAGE->set_title($streditingquestions);
@@ -10,8 +10,8 @@ Feature: Use the qbank plugin manager page for question history
| activity | name | course | idnumber |
| quiz | Test quiz | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
@@ -42,8 +42,8 @@ Feature: Use the qbank plugin manager page for question history
@javascript
Scenario: Viewing history for a question in a non-default category
Given the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions 2 |
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions 2 |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions 2 | truefalse | Second question | Answer the second question |
@@ -10,8 +10,8 @@ Feature: Use the qbank plugin manager page for version column
| activity | name | course | idnumber |
| quiz | Test quiz | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
| contextlevel | reference | name |
| Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
+6 -6
View File
@@ -80,16 +80,16 @@ class helper_test extends \advanced_testcase {
public function test_question_history_url(): void {
$this->resetAfterTest();
$filter = urlencode('filters[]');
$actionurl = helper::question_history_url(
$actionurl = helper::get_question_history_url(
$this->questiondata->questionbankentryid,
$this->returnurl,
$this->courseid,
$this->context->instanceid,
$filter,
);
$params = [
'entryid' => $this->questiondata->questionbankentryid,
'returnurl' => $this->returnurl,
'courseid' => $this->courseid,
'cmid' => $this->context->instanceid,
'filter' => $filter,
];
$expectedurl = new \moodle_url('/question/bank/history/history.php', $params);
@@ -103,16 +103,16 @@ class helper_test extends \advanced_testcase {
*/
public function test_question_history_url_null_filter(): void {
$this->resetAfterTest();
$actionurl = helper::question_history_url(
$actionurl = helper::get_question_history_url(
$this->questiondata->questionbankentryid,
$this->returnurl,
$this->courseid,
$this->context->instanceid,
null,
);
$params = [
'entryid' => $this->questiondata->questionbankentryid,
'returnurl' => $this->returnurl,
'courseid' => $this->courseid,
'cmid' => $this->context->instanceid,
];
$expectedurl = new \moodle_url('/question/bank/history/history.php', $params);
$this->assertEquals($expectedurl, $actionurl);
@@ -46,6 +46,7 @@ class question_history_view_test extends \advanced_testcase {
// Create a course.
$course = $generator->create_course();
$qbank = $generator->create_module('qbank', ['course' => $course->id]);
$cm = get_coursemodule_from_id('qbank', $qbank->cmid);
$context = \context_module::instance($qbank->cmid);
// Create a question in the default category.
@@ -73,7 +74,7 @@ class question_history_view_test extends \advanced_testcase {
'entryid' => $entry->id,
'returnurl' => "/",
];
$view = new $viewclass($contexts, new \moodle_url('/'), $course, null, $pagevars, $extraparams);
$view = new $viewclass($contexts, new \moodle_url('/'), $course, $cm, $pagevars, $extraparams);
ob_start();
$view->display();
$html = ob_get_clean();
@@ -98,6 +99,8 @@ class question_history_view_test extends \advanced_testcase {
// Create a course.
$course = $generator->create_course();
$qbank = $generator->create_module('qbank', ['course' => $course->id]);
$cm = get_coursemodule_from_id('qbank', $qbank->cmid);
$context = \context_course::instance($course->id);
// Create a question in the default category.
@@ -120,7 +123,7 @@ class question_history_view_test extends \advanced_testcase {
'entryid' => $entry->id,
'returnurl' => "/",
];
$view = new $viewclass($contexts, new \moodle_url('/'), $course, null, $pagevars, $extraparams);
$view = new $viewclass($contexts, new \moodle_url('/'), $course, $cm, $pagevars, $extraparams);
ob_start();
$view->display_question_bank_header();
$headerhtml = ob_get_clean();
@@ -129,7 +132,7 @@ class question_history_view_test extends \advanced_testcase {
$questiondata2 = $questiongenerator->update_question($questiondata1, null,
['name' => 'Second version']);
$view = new $viewclass($contexts, new \moodle_url('/'), $course, null, $pagevars, $extraparams);
$view = new $viewclass($contexts, new \moodle_url('/'), $course, $cm, $pagevars, $extraparams);
ob_start();
$view->display_question_bank_header();
$headerhtml = ob_get_clean();
+3 -7
View File
@@ -48,17 +48,13 @@ if (!$category = $DB->get_record("question_categories", ['id' => $catid])) {
$categorycontext = context::instance_by_id($category->contextid);
$category->context = $categorycontext;
// This page can be called without courseid or cmid in which case.
// This page can be called without cmid in which case.
// We get the context from the category object.
if ($contexts === null) { // Need to get the course from the chosen category.
$contexts = new core_question\local\bank\question_edit_contexts($categorycontext);
$thiscontext = $contexts->lowest();
if ($thiscontext->contextlevel == CONTEXT_COURSE) {
require_login($thiscontext->instanceid, false);
} else if ($thiscontext->contextlevel == CONTEXT_MODULE) {
list($module, $cm) = get_module_from_cmid($thiscontext->instanceid);
require_login($cm->course, false, $cm);
}
[$module, $cm] = get_module_from_cmid($thiscontext->instanceid);
require_login($cm->course, false, $cm);
$contexts->require_one_edit_tab_cap($edittab);
}
+10 -8
View File
@@ -37,16 +37,15 @@ use qbank_managecategories\question_categories;
require_login();
core_question\local\bank\helper::require_plugin_enabled(helper::PLUGINNAME);
// Since Moodle 5.0 any request with the courseid parameter is deprecated and will redirect to the banks management page.
if ($courseid = optional_param('courseid', 0, PARAM_INT)) {
redirect(new moodle_url('/question/banks.php', ['courseid' => $courseid]));
}
list($thispageurl, $contexts, $cmid, $cm, $module, $pagevars) =
question_edit_setup('categories', '/question/bank/managecategories/category.php');
$courseid = optional_param('courseid', 0, PARAM_INT);
if (!is_null($cmid)) {
$thiscontext = context_module::instance($cmid)->id;
} else {
$course = get_course($courseid);
$thiscontext = context_course::instance($course->id)->id;
}
$thiscontext = context_module::instance($cmid)->id;
$todelete = optional_param('delete', 0, PARAM_INT); // The ID of a category to delete.
@@ -112,10 +111,13 @@ if ($questionstomove) {
echo $OUTPUT->box(get_string('categorymove', 'question', $vars), 'generalbox boxaligncenter');
$moveform->display();
} else {
// Get module contexts we have capabilities to manage.
$contextswithcaps = $contexts->having_one_edit_tab_cap('categories');
$modcontexts = array_filter($contextswithcaps, static fn ($context) => $context->contextlevel === CONTEXT_MODULE);
// Display the user interface.
$questioncategories = new question_categories(
$thispageurl,
$contexts->having_one_edit_tab_cap('categories'),
$modcontexts,
$cmid,
$courseid,
$thiscontext,
@@ -32,6 +32,9 @@ class category_condition extends condition {
/** @var \stdClass The course record. */
protected $course;
/** @var \stdClass The course_modules record. */
protected \stdClass $cm;
/** @var \stdClass The category record. */
protected $category;
@@ -61,6 +64,7 @@ class category_condition extends condition {
static fn($context) => $context->contextlevel === CONTEXT_MODULE
);
$this->course = $qbank->course;
$this->cm = $qbank->cm;
[$categoryid, $contextid] = self::validate_category_param($this->cat);
if (is_null($categoryid)) {
@@ -74,14 +78,13 @@ class category_condition extends condition {
}
/**
* MDL-71378 TODO: Not used and to be deprecated anyway
* Return default category
*
* @return \stdClass default category
*/
public function get_default_category(): \stdClass {
if (empty($this->category)) {
return question_get_default_category(\context_course::instance($this->course->id)->id);
return question_get_default_category(\context_module::instance($this->cm->id)->id, true);
}
return $this->category;
@@ -86,6 +86,10 @@ class question_categories {
fields: 'contextid, id'
);
foreach ($contexts as $context) {
// We can only have categories in module context.
if ($context->contextlevel !== CONTEXT_MODULE) {
continue;
}
$items = helper::get_categories_for_contexts($context->id);
// Create an ordered tree with children correctly nested under parents.
foreach ($items as $item) {
@@ -87,12 +87,8 @@ class question_category_list_item extends \list_item {
$str = $extraargs['str'];
$category = $this->item;
// Each section adds html to be displayed as part of this list item.
$nodeparent = $PAGE->settingsnav->find('questionbank', \navigation_node::TYPE_CONTAINER);
$questionbankurl = new moodle_url('/question/edit.php', $this->parentlist->pageurl->params());
// The category URL is based on the node action.
$questionbankurl = new moodle_url($nodeparent->action->out_omit_querystring(),
$this->parentlist->pageurl->params());
$questionbankurl->param('cat', $category->id . ',' . $category->contextid);
$categoryname = format_string($category->name, true, ['context' => $this->parentlist->context]);

Some files were not shown because too many files have changed in this diff Show More