From a0cf3d2da53afe3c93ca99de071e0a7356271a9c Mon Sep 17 00:00:00 2001
From: Simon Adams
Date: Fri, 16 Aug 2024 09:37:40 +0100
Subject: [PATCH] MDL-71378 core_question & mod_quiz: Refactor deprecated
contexts
---
.upgradenotes/MDL-71378-2024070813542859.yml | 17 +
.upgradenotes/MDL-71378-2024070813572581.yml | 42 +
.../local/areas/core_question/answerbase.php | 13 +-
.../local/areas/core_question/base.php | 29 +-
admin/tool/brickfield/tests/area_test.php | 44 +-
.../core_question/questionanswers_test.php | 132 +--
.../areas/core_question/questiontext_test.php | 149 +--
backup/moodle2/restore_stepslib.php | 12 +-
course/classes/category.php | 9 -
lang/en/error.php | 4 +-
lang/en/question.php | 4 +-
lib/classes/event/question_base.php | 16 +-
lib/classes/event/question_category_base.php | 10 +-
lib/classes/event/question_moved.php | 13 +-
lib/classes/event/questions_exported.php | 10 +-
lib/classes/event/questions_imported.php | 10 +-
lib/moodlelib.php | 6 -
lib/questionlib.php | 225 +---
.../behat/menu_navigation_topics.feature | 2 +-
lib/tests/navigation/views/secondary_test.php | 2 +-
lib/tests/questionlib_test.php | 1047 ++---------------
mod/quiz/classes/structure.php | 28 +-
mod/quiz/edit.php | 2 +-
mod/quiz/editgrading.php | 2 +-
mod/quiz/lang/en/deprecated.txt | 3 +
mod/quiz/lang/en/quiz.php | 9 +-
.../overview/tests/behat/regrading.feature | 6 +-
mod/quiz/tests/behat/attempt_basic.feature | 17 +-
mod/quiz/tests/behat/attempt_begin.feature | 7 +-
.../behat/attempt_multiple_grades.feature | 10 +-
.../behat/attempt_require_previous.feature | 7 +-
.../behat/attempt_review_options.feature | 7 +-
.../tests/behat/attempt_sequential.feature | 10 +-
mod/quiz/tests/behat/behat_mod_quiz.php | 5 +-
...completion_condition_attempts_used.feature | 12 +-
.../tests/behat/completion_manual.feature | 12 +-
mod/quiz/tests/behat/editing_add.feature | 29 +-
.../tests/behat/editing_move_by_click.feature | 10 +-
.../behat/editing_multiple_grades.feature | 10 +-
.../behat/editing_question_numbering.feature | 13 +-
.../editing_remove_multiple_questions.feature | 10 +-
.../behat/editing_remove_question.feature | 10 +-
.../behat/editing_require_previous.feature | 7 +-
.../behat/editing_section_headings.feature | 7 +-
.../editing_set_marks_no_attempts.feature | 8 +-
.../tests/behat/editing_switch_bank.feature | 7 -
.../behat/feedback_on_override_mark.feature | 10 +-
mod/quiz/tests/behat/flag_questions.feature | 17 +-
mod/quiz/tests/behat/group_mode.feature | 5 +-
mod/quiz/tests/behat/info_page.feature | 7 +-
.../behat/manually_mark_question.feature | 11 +-
mod/quiz/tests/behat/preview.feature | 10 +-
.../behat/quiz_activity_availability.feature | 7 +-
.../behat/quiz_activity_certainty.feature | 10 +-
.../behat/quiz_activity_completion.feature | 12 +-
.../quiz_activity_completion_locked.feature | 12 +-
.../quiz_activity_completion_unlocked.feature | 14 +-
mod/quiz/tests/behat/quiz_feedback.feature | 7 +-
.../quiz_interactive_multiple_tries.feature | 10 +-
.../behat/quiz_question_versions.feature | 10 +-
mod/quiz/tests/behat/quiz_reset.feature | 12 +-
mod/quiz/tests/behat/random_question.feature | 35 +-
mod/quiz/tests/behat/reattempt_quiz.feature | 10 +-
.../settings_form_fields_disableif.feature | 9 +-
mod/quiz/tests/quiz_question_restore_test.php | 11 +-
.../classes/column_manager.php | 2 +-
.../tests/behat/question_bank.feature | 2 +-
.../tests/column_manager_test.php | 4 +-
question/bank/comment/tests/backup_test.php | 3 +-
.../tests/behat/question_comment.feature | 4 +-
.../behat/question_comment_column.feature | 4 +-
question/bank/comment/tests/lib_test.php | 6 +-
.../customfields/tests/customfield_test.php | 3 +-
.../tests/question_handler_test.php | 5 +-
.../deletequestion/classes/delete_action.php | 8 +-
question/bank/deletequestion/delete.php | 17 +-
.../behat/delete_question_column.feature | 5 +-
question/bank/editquestion/addquestion.php | 29 +-
.../bank/editquestion/classes/copy_action.php | 6 +-
.../bank/editquestion/classes/edit_action.php | 6 +-
question/bank/editquestion/question.php | 34 +-
.../tests/behat/qbank_editquestion.feature | 4 +-
.../tests/behat/question_status.feature | 4 +-
question/bank/exporttoxml/classes/helper.php | 18 +-
question/bank/exporttoxml/exportone.php | 20 +-
.../tests/behat/export_to_xml_action.feature | 4 +-
.../tests/behat/preview_question.feature | 7 +-
question/bank/history/classes/helper.php | 27 +
.../bank/history/classes/history_action.php | 4 +-
.../history/classes/question_history_view.php | 4 +
question/bank/history/history.php | 2 +-
.../behat/question_history_action.feature | 8 +-
.../behat/question_version_column.feature | 4 +-
question/bank/history/tests/helper_test.php | 12 +-
.../tests/question_history_view_test.php | 9 +-
question/bank/importquestions/import.php | 10 +-
question/bank/managecategories/category.php | 18 +-
.../classes/category_condition.php | 7 +-
.../classes/question_categories.php | 4 +
.../classes/question_category_list_item.php | 6 +-
.../behat/move_question_categories.feature | 51 +-
.../tests/behat/question_categories.feature | 45 +-
.../question_categories_idnumber.feature | 21 +-
.../view_manage_categories_plugin.feature | 4 +-
.../tests/external/move_category_test.php | 142 +--
.../managecategories/tests/helper_test.php | 2 +-
.../tests/manage_category_test_base.php | 46 +-
.../tests/question_categories_test.php | 16 +-
.../bank/previewquestion/classes/helper.php | 24 +-
question/bank/previewquestion/preview.php | 7 +-
.../tests/behat/preview_question.feature | 4 +-
.../behat/preview_question_action.feature | 4 +-
.../tests/qbank_preview_helper_test.php | 12 +-
.../tests/behat/statistics_action.feature | 4 +-
.../tests/behat/statistics_values.feature | 23 +-
.../classes/external/submit_tags.php | 25 +-
.../tagquestion/classes/form/tags_form.php | 19 -
question/bank/tagquestion/lib.php | 10 +-
.../tests/behat/tag_question_action.feature | 4 +-
.../tests/external/submit_tags_test.php | 176 ---
.../behat/question_last_used_column.feature | 4 +-
.../tests/behat/question_usage_column.feature | 5 +-
.../behat/view_view_creator_column.feature | 4 +-
.../behat/question_in_place_editing.feature | 4 +-
.../behat/view_question_name_column.feature | 4 +-
.../behat/view_question_text_column.feature | 4 +-
.../behat/view_question_type_column.feature | 4 +-
question/classes/local/bank/view.php | 15 +-
.../output/question_bank_filter_ui.php | 14 +-
question/edit.php | 5 +
question/editlib.php | 44 +-
question/format.php | 54 +-
.../aiken/tests/behat/aiken_export.feature | 9 +-
.../aiken/tests/behat/aiken_import.feature | 5 +-
.../aiken/tests/qformat_aiken_export_test.php | 6 +-
question/format/gift/format.php | 2 +-
.../gift/tests/behat/import_export.feature | 7 +-
question/format/xml/format.php | 2 +-
.../xml/tests/behat/import_export.feature | 13 +-
.../fixtures/categories_reverse_order.xml | 4 +-
.../fixtures/category_with_description.xml | 2 +-
.../tests/fixtures/deprecated_category.xml | 40 +
.../xml/tests/fixtures/export_category.xml | 2 +-
.../fixtures/html_chars_in_idnumbers.xml | 2 +-
.../format/xml/tests/fixtures/multianswer.xml | 2 +-
.../format/xml/tests/fixtures/multichoice.xml | 2 +-
.../xml/tests/fixtures/nested_categories.xml | 6 +-
.../nested_categories_with_questions.xml | 8 +-
.../xml/tests/fixtures/old_format_file.xml | 4 +-
.../sample_questions_with_old_image_tag.xml | 2 +-
.../format/xml/tests/fixtures/truefalse.xml | 2 +-
.../tests/qformat_xml_import_export_test.php | 61 +-
question/templates/qbank_action_menu.mustache | 8 +-
question/tests/backup_test.php | 13 +-
.../behat/bank_add_default_shared.feature | 1 -
question/tests/behat/bank_view.feature | 13 +-
question/tests/behat/behat_core_question.php | 64 +-
question/tests/behat/delete_questions.feature | 13 +-
.../tests/behat/duplicate_questions.feature | 9 +-
.../tests/behat/edit_question_tags.feature | 9 +-
.../behat/edit_question_versioning.feature | 10 +-
question/tests/behat/edit_questions.feature | 13 +-
.../edit_questions_standard_tags.feature | 5 +-
.../behat/filter_questions_by_tag.feature | 10 +-
...lter_questions_combined_conditions.feature | 12 +-
.../tests/behat/question_categories.feature | 39 -
.../question_categories_idnumber.feature | 39 +-
.../behat/question_filter_pagination.feature | 11 +-
.../tests/behat/question_highlight.feature | 7 +-
question/tests/behat/select_questions.feature | 9 +-
question/tests/behat/sort_questions.feature | 10 +-
question/tests/category_manager_test.php | 37 +-
question/tests/generator/lib.php | 19 +
question/tests/privacy/provider_test.php | 26 +-
question/tests/question_bank_column_test.php | 10 +-
.../calculated/tests/question_type_test.php | 2 +-
question/type/essay/tests/restore_test.php | 2 +-
.../gapselect/tests/behat/import_test.feature | 1 +
.../multianswer/tests/question_type_test.php | 2 +-
question/type/questiontypebase.php | 2 +
.../truefalse/tests/question_type_test.php | 2 +-
.../tests/behat/question_reports.feature | 24 +-
...ehat_theme_classic_behat_core_question.php | 11 +-
183 files changed, 1266 insertions(+), 2721 deletions(-)
create mode 100644 .upgradenotes/MDL-71378-2024070813542859.yml
create mode 100644 .upgradenotes/MDL-71378-2024070813572581.yml
create mode 100644 question/format/xml/tests/fixtures/deprecated_category.xml
delete mode 100644 question/tests/behat/question_categories.feature
diff --git a/.upgradenotes/MDL-71378-2024070813542859.yml b/.upgradenotes/MDL-71378-2024070813542859.yml
new file mode 100644
index 00000000000..6f8a98b0390
--- /dev/null
+++ b/.upgradenotes/MDL-71378-2024070813542859.yml
@@ -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
diff --git a/.upgradenotes/MDL-71378-2024070813572581.yml b/.upgradenotes/MDL-71378-2024070813572581.yml
new file mode 100644
index 00000000000..5acaf7a941b
--- /dev/null
+++ b/.upgradenotes/MDL-71378-2024070813572581.yml
@@ -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
diff --git a/admin/tool/brickfield/classes/local/areas/core_question/answerbase.php b/admin/tool/brickfield/classes/local/areas/core_question/answerbase.php
index 66c96fbee78..fa824dc7923 100644
--- a/admin/tool/brickfield/classes/local/areas/core_question/answerbase.php
+++ b/admin/tool/brickfield/classes/local/areas/core_question/answerbase.php
@@ -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);
diff --git a/admin/tool/brickfield/classes/local/areas/core_question/base.php b/admin/tool/brickfield/classes/local/areas/core_question/base.php
index 195b3da8857..be04ff035b6 100644
--- a/admin/tool/brickfield/classes/local/areas/core_question/base.php
+++ b/admin/tool/brickfield/classes/local/areas/core_question/base.php
@@ -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';
diff --git a/admin/tool/brickfield/tests/area_test.php b/admin/tool/brickfield/tests/area_test.php
index f3b2d4b8084..9432fc28e7e 100644
--- a/admin/tool/brickfield/tests/area_test.php
+++ b/admin/tool/brickfield/tests/area_test.php
@@ -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,
diff --git a/admin/tool/brickfield/tests/local/areas/core_question/questionanswers_test.php b/admin/tool/brickfield/tests/local/areas/core_question/questionanswers_test.php
index 6e9ecd2b02b..dae564cb2c0 100644
--- a/admin/tool/brickfield/tests/local/areas/core_question/questionanswers_test.php
+++ b/admin/tool/brickfield/tests/local/areas/core_question/questionanswers_test.php
@@ -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);
- }
}
diff --git a/admin/tool/brickfield/tests/local/areas/core_question/questiontext_test.php b/admin/tool/brickfield/tests/local/areas/core_question/questiontext_test.php
index 522e056d9fa..36622a6a9fd 100644
--- a/admin/tool/brickfield/tests/local/areas/core_question/questiontext_test.php
+++ b/admin/tool/brickfield/tests/local/areas/core_question/questiontext_test.php
@@ -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();
}
}
diff --git a/backup/moodle2/restore_stepslib.php b/backup/moodle2/restore_stepslib.php
index 41ad4e4ed72..3f72c09ef8e 100644
--- a/backup/moodle2/restore_stepslib.php
+++ b/backup/moodle2/restore_stepslib.php
@@ -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));
diff --git a/course/classes/category.php b/course/classes/category.php
index 86b6abb17ad..07716ccc216 100644
--- a/course/classes/category.php
+++ b/course/classes/category.php
@@ -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();
diff --git a/lang/en/error.php b/lang/en/error.php
index 68c808b5ccf..64a6385ede1 100644
--- a/lang/en/error.php
+++ b/lang/en/error.php
@@ -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}\'';
diff --git a/lang/en/question.php b/lang/en/question.php
index 2dd7cbd77de..961095d64bf 100644
--- a/lang/en/question.php
+++ b/lang/en/question.php
@@ -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}.';
diff --git a/lib/classes/event/question_base.php b/lib/classes/event/question_base.php
index 0db7da5d7a0..12c24656f2d 100644
--- a/lib/classes/event/question_base.php
+++ b/lib/classes/event/question_base.php
@@ -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]
+ );
}
/**
diff --git a/lib/classes/event/question_category_base.php b/lib/classes/event/question_category_base.php
index c3b082c1a10..c516ed6fe3a 100644
--- a/lib/classes/event/question_category_base.php
+++ b/lib/classes/event/question_category_base.php
@@ -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]);
}
/**
diff --git a/lib/classes/event/question_moved.php b/lib/classes/event/question_moved.php
index 6956d930f61..710ee8f8efc 100644
--- a/lib/classes/event/question_moved.php
+++ b/lib/classes/event/question_moved.php
@@ -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]
+ );
}
/**
diff --git a/lib/classes/event/questions_exported.php b/lib/classes/event/questions_exported.php
index 46c608be5e4..0d3a5a66fe5 100644
--- a/lib/classes/event/questions_exported.php
+++ b/lib/classes/event/questions_exported.php
@@ -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]);
}
/**
diff --git a/lib/classes/event/questions_imported.php b/lib/classes/event/questions_imported.php
index ef0e0bd0c93..a1844d5e55f 100644
--- a/lib/classes/event/questions_imported.php
+++ b/lib/classes/event/questions_imported.php
@@ -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]);
}
/**
diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index 22fd699a4be..093ee1dfb03 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -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);
diff --git a/lib/questionlib.php b/lib/questionlib.php
index 71b67bc494a..448dcc04ea2 100644
--- a/lib/questionlib.php
+++ b/lib/questionlib.php
@@ -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;
}
/**
diff --git a/lib/tests/behat/menu_navigation_topics.feature b/lib/tests/behat/menu_navigation_topics.feature
index e1c37a888b2..beb09dd4d5e 100644
--- a/lib/tests/behat/menu_navigation_topics.feature
+++ b/lib/tests/behat/menu_navigation_topics.feature
@@ -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
diff --git a/lib/tests/navigation/views/secondary_test.php b/lib/tests/navigation/views/secondary_test.php
index 21cae6d1100..6036ac3d897 100644
--- a/lib/tests/navigation/views/secondary_test.php
+++ b/lib/tests/navigation/views/secondary_test.php
@@ -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" => [
diff --git a/lib/tests/questionlib_test.php b/lib/tests/questionlib_test.php
index 601f745bee2..df16d1ddb2c 100644
--- a/lib/tests/questionlib_test.php
+++ b/lib/tests/questionlib_test.php
@@ -50,13 +50,22 @@ class questionlib_test extends \advanced_testcase {
$this->resetAfterTest();
}
+ /**
+ * Generate a course and question bank module instance for use in test cases, and return the bank context.
+ * @return \core\context\module
+ */
+ protected function create_course_and_question_bank(): \core\context\module {
+ $course = self::getDataGenerator()->create_course();
+ $qbank = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
+ return \context_module::instance($qbank->cmid);
+ }
+
/**
* Setup a course, a quiz, a question category and a question for testing.
*
- * @param string $type The type of question category to create.
* @return array The created data objects
*/
- public function setup_quiz_and_questions($type = 'module') {
+ public function setup_quiz_and_questions() {
// Create course category.
$category = $this->getDataGenerator()->create_category();
@@ -77,23 +86,7 @@ class questionlib_test extends \advanced_testcase {
/** @var \core_question_generator $qgen */
$qgen = $this->getDataGenerator()->get_plugin_generator('core_question');
- switch ($type) {
- case 'course':
- $context = \context_course::instance($course->id);
- break;
-
- case 'category':
- $context = \context_coursecat::instance($category->id);
- break;
-
- case 'system':
- $context = \context_system::instance();
- break;
-
- default:
- $context = \context_module::instance($quiz->cmid);
- break;
- }
+ $context = \context_module::instance($quiz->cmid);
$qcat = $qgen->create_question_category(array('contextid' => $context->id));
@@ -278,7 +271,7 @@ class questionlib_test extends \advanced_testcase {
global $DB;
// Setup.
- $context = \context_system::instance();
+ $context = $this->create_course_and_question_bank();
/** @var \core_question_generator $qgen */
$qgen = $this->getDataGenerator()->get_plugin_generator('core_question');
$qcat = $qgen->create_question_category(array('contextid' => $context->id));
@@ -301,7 +294,7 @@ class questionlib_test extends \advanced_testcase {
global $DB;
// Setup.
- $context = \context_system::instance();
+ $context = $this->create_course_and_question_bank();
/** @var \core_question_generator $qgen */
$qgen = $this->getDataGenerator()->get_plugin_generator('core_question');
$qcat = $qgen->create_question_category(array('contextid' => $context->id));
@@ -328,8 +321,7 @@ class questionlib_test extends \advanced_testcase {
public function test_question_delete_question_missing_context(): void {
global $DB;
- $coursecategory = $this->getDataGenerator()->create_category();
- $context = $coursecategory->get_context();
+ $context = $this->create_course_and_question_bank();
/** @var \core_question_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
@@ -398,6 +390,8 @@ class questionlib_test extends \advanced_testcase {
/**
* This function tests the question_delete_context function.
+ *
+ * @covers ::question_delete_context()
*/
public function test_question_delete_context(): void {
global $DB;
@@ -410,110 +404,31 @@ class questionlib_test extends \advanced_testcase {
$result = question_delete_context($qcat->contextid);
// Verify category deleted.
- $criteria = array('id' => $qcat->id);
+ $criteria = ['id' => $qcat->id];
$this->assertEquals(0, $DB->count_records('question_categories', $criteria));
// Verify questions deleted or moved.
$this->assert_category_contains_questions($qcat->id, 0);
}
- /**
- * This function tests the question_delete_course function.
- */
- public function test_question_delete_course(): void {
- global $DB;
- $this->resetAfterTest(true);
- $this->setAdminUser();
-
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('course');
-
- // Test the deletion.
- question_delete_course($course);
-
- // Verify category deleted.
- $criteria = array('id' => $qcat->id);
- $this->assertEquals(0, $DB->count_records('question_categories', $criteria));
-
- // Verify questions deleted or moved.
- $this->assert_category_contains_questions($qcat->id, 0);
- }
-
- /**
- * This function tests the question_delete_course_category function.
- */
- public function test_question_delete_course_category(): void {
- global $DB;
- $this->resetAfterTest(true);
- $this->setAdminUser();
-
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category');
-
- // Test that the feedback works.
- question_delete_course_category($category, null);
-
- // Verify category deleted.
- $criteria = array('id' => $qcat->id);
- $this->assertEquals(0, $DB->count_records('question_categories', $criteria));
-
- // Verify questions deleted or moved.
- $this->assert_category_contains_questions($qcat->id, 0);
- }
-
- /**
- * This function tests the question_delete_course_category function when it is supposed to move question categories.
- */
- public function test_question_delete_course_category_move_qcats(): void {
- global $DB;
- $this->resetAfterTest(true);
- $this->setAdminUser();
-
- list($category1, $course1, $quiz1, $qcat1, $questions1) = $this->setup_quiz_and_questions('category');
- list($category2, $course2, $quiz2, $qcat2, $questions2) = $this->setup_quiz_and_questions('category');
-
- $questionsinqcat1 = count($questions1);
- $questionsinqcat2 = count($questions2);
-
- // Test the delete.
- question_delete_course_category($category1, $category2);
-
- // Verify category not deleted.
- $criteria = array('id' => $qcat1->id);
- $this->assertEquals(1, $DB->count_records('question_categories', $criteria));
-
- // Verify questions are moved.
- $params = array($qcat2->contextid);
- $actualquestionscount = $DB->count_records_sql("SELECT COUNT(*)
- FROM {question} q
- JOIN {question_versions} qv ON qv.questionid = q.id
- JOIN {question_bank_entries} qbe ON qbe.id = qv.questionbankentryid
- JOIN {question_categories} qc ON qc.id = qbe.questioncategoryid
- WHERE qc.contextid = ?", $params);
- $this->assertEquals($questionsinqcat1 + $questionsinqcat2, $actualquestionscount);
-
- // Verify there is just a single top-level category.
- $criteria = array('contextid' => $qcat2->contextid, 'parent' => 0);
- $this->assertEquals(1, $DB->count_records('question_categories', $criteria));
-
- // Verify there is no question category in previous context.
- $criteria = array('contextid' => $qcat1->contextid);
- $this->assertEquals(0, $DB->count_records('question_categories', $criteria));
- }
-
/**
* This function tests the question_save_from_deletion function when it is supposed to make a new category and
* move question categories to that new category.
+ *
+ * @covers ::question_save_from_deletion()
*/
public function test_question_save_from_deletion(): void {
global $DB;
$this->resetAfterTest(true);
$this->setAdminUser();
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions();
+ [$category, $course, $quiz, $qcat, $questions] = $this->setup_quiz_and_questions();
+ $qbank = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
+ $qbankcontext = \context_module::instance($qbank->cmid);
$context = \context::instance_by_id($qcat->contextid);
- $newcat = question_save_from_deletion(array_column($questions, 'id'),
- $context->get_parent_context()->id, $context->get_context_name());
+ $newcat = question_save_from_deletion(array_column($questions, 'id'), $qbankcontext->id, $context->get_context_name());
// Verify that the newcat itself is not a tep level category.
$this->assertNotEquals(0, $newcat->parent);
@@ -525,13 +440,17 @@ class questionlib_test extends \advanced_testcase {
/**
* This function tests the question_save_from_deletion function when it is supposed to make a new category and
* move question categories to that new category when quiz name is very long but less than 256 characters.
+ *
+ * @covers ::question_save_from_deletion()
*/
public function test_question_save_from_deletion_quiz_with_long_name(): void {
global $DB;
$this->resetAfterTest(true);
$this->setAdminUser();
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions();
+ [$category, $course, $quiz, $qcat, $questions] = $this->setup_quiz_and_questions();
+ $qbank = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
+ $qbankcontext = \context_module::instance($qbank->cmid);
// Moodle doesn't allow you to enter a name longer than 255 characters.
$quiz->name = shorten_text(str_repeat('123456789 ', 26), 255);
@@ -540,8 +459,7 @@ class questionlib_test extends \advanced_testcase {
$context = \context::instance_by_id($qcat->contextid);
- $newcat = question_save_from_deletion(array_column($questions, 'id'),
- $context->get_parent_context()->id, $context->get_context_name());
+ $newcat = question_save_from_deletion(array_column($questions, 'id'), $qbankcontext->id, $context->get_context_name());
// Verifying that the inserted record's name is expected or not.
$this->assertEquals($DB->get_record('question_categories', ['id' => $newcat->id])->name, $newcat->name);
@@ -555,9 +473,11 @@ class questionlib_test extends \advanced_testcase {
/**
* get_question_options should add the category object to the given question.
+ *
+ * @covers ::get_question_options()
*/
public function test_get_question_options_includes_category_object_single_question(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category');
+ [$category, $course, $quiz, $qcat, $questions] = $this->setup_quiz_and_questions();
$question = array_shift($questions);
get_question_options($question);
@@ -568,9 +488,11 @@ class questionlib_test extends \advanced_testcase {
/**
* get_question_options should add the category object to all of the questions in
* the given list.
+ *
+ * @covers ::get_question_options()
*/
public function test_get_question_options_includes_category_object_multiple_questions(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category');
+ [$category, $course, $quiz, $qcat, $questions] = $this->setup_quiz_and_questions();
get_question_options($questions);
@@ -581,9 +503,11 @@ class questionlib_test extends \advanced_testcase {
/**
* get_question_options includes the tags for all questions in the list.
+ *
+ * @covers ::get_question_options()
*/
public function test_get_question_options_includes_question_tags(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category');
+ [$category, $course, $quiz, $qcat, $questions] = $this->setup_quiz_and_questions();
$question1 = $questions[0];
$question2 = $questions[1];
$qcontext = \context::instance_by_id($qcat->contextid);
@@ -611,130 +535,6 @@ class questionlib_test extends \advanced_testcase {
// The question should have a full set of each tag object.
$this->assertEquals($tags, $actualtagobjects);
- // The question should not have any course tags.
- $this->assertEmpty($question->coursetagobjects);
- }
- }
-
- /**
- * get_question_options includes the course tags for all questions in the list.
- */
- public function test_get_question_options_includes_course_tags(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category');
- $question1 = $questions[0];
- $question2 = $questions[1];
- $coursecontext = \context_course::instance($course->id);
-
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['foo', 'bar']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['baz', 'bop']);
-
- get_question_options($questions, true);
-
- foreach ($questions as $question) {
- $tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
- $expectedcoursetags = [];
- $actualcoursetags = $question->coursetags;
- foreach ($tags as $tag) {
- $expectedcoursetags[$tag->id] = $tag->get_display_name();
- }
-
- // The question should have a coursetags property populated with each tag id
- // and display name as a key vale pair.
- $this->assertEquals($expectedcoursetags, $actualcoursetags);
-
- $actualcoursetagobjects = $question->coursetagobjects;
- sort($tags);
- sort($actualcoursetagobjects);
-
- // The question should have a full set of the course tag objects.
- $this->assertEquals($tags, $actualcoursetagobjects);
- // The question should not have any other tags.
- $this->assertEmpty($question->tagobjects);
- $this->assertEmpty($question->tags);
- }
- }
-
- /**
- * get_question_options only categorises a tag as a course tag if it is in a
- * course context that is different from the question context.
- */
- public function test_get_question_options_course_tags_in_course_question_context(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('course');
- $question1 = $questions[0];
- $question2 = $questions[1];
- $coursecontext = \context_course::instance($course->id);
-
- // Create course level tags in the course context that matches the question
- // course context.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['foo', 'bar']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['baz', 'bop']);
-
- get_question_options($questions, true);
-
- foreach ($questions as $question) {
- $tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
-
- $actualtagobjects = $question->tagobjects;
- sort($tags);
- sort($actualtagobjects);
-
- // The tags should not be considered course tags because they are in
- // the same context as the question. That makes them question tags.
- $this->assertEmpty($question->coursetagobjects);
- // The course context tags should be returned in the regular tag object
- // list.
- $this->assertEquals($tags, $actualtagobjects);
- }
- }
-
- /**
- * get_question_options includes the tags and course tags for all questions in the list
- * if each question has course and question level tags.
- */
- public function test_get_question_options_includes_question_and_course_tags(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category');
- $question1 = $questions[0];
- $question2 = $questions[1];
- $qcontext = \context::instance_by_id($qcat->contextid);
- $coursecontext = \context_course::instance($course->id);
-
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo', 'bar']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['cfoo', 'cbar']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['baz', 'bop']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['cbaz', 'cbop']);
-
- get_question_options($questions, true);
-
- foreach ($questions as $question) {
- $alltags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
- $tags = array_filter($alltags, function($tag) use ($qcontext) {
- return $tag->taginstancecontextid == $qcontext->id;
- });
- $coursetags = array_filter($alltags, function($tag) use ($coursecontext) {
- return $tag->taginstancecontextid == $coursecontext->id;
- });
-
- $expectedtags = [];
- $actualtags = $question->tags;
- foreach ($tags as $tag) {
- $expectedtags[$tag->id] = $tag->get_display_name();
- }
-
- // The question should have a tags property populated with each tag id
- // and display name as a key vale pair.
- $this->assertEquals($expectedtags, $actualtags);
-
- $actualtagobjects = $question->tagobjects;
- sort($tags);
- sort($actualtagobjects);
- // The question should have a full set of each tag object.
- $this->assertEquals($tags, $actualtagobjects);
-
- $actualcoursetagobjects = $question->coursetagobjects;
- sort($coursetags);
- sort($actualcoursetagobjects);
- // The question should have a full set of course tag objects.
- $this->assertEquals($coursetags, $actualcoursetagobjects);
}
}
@@ -742,9 +542,11 @@ class questionlib_test extends \advanced_testcase {
* get_question_options should update the context id to the question category
* context id for any non-course context tag that isn't in the question category
* context.
+ *
+ * @covers ::get_question_options()
*/
public function test_get_question_options_normalises_question_tags(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category');
+ list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions();
$question1 = $questions[0];
$question2 = $questions[1];
$qcontext = \context::instance_by_id($qcat->contextid);
@@ -782,606 +584,33 @@ class questionlib_test extends \advanced_testcase {
}
/**
- * get_question_options if the question is a course level question then tags
- * in that context should not be consdered course tags, they are question tags.
- */
- public function test_get_question_options_includes_course_context_question_tags(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('course');
- $question1 = $questions[0];
- $question2 = $questions[1];
- $coursecontext = \context_course::instance($course->id);
-
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['foo', 'bar']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['baz', 'bop']);
-
- get_question_options($questions, true);
-
- foreach ($questions as $question) {
- $tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
- // Tags in a course context that matches the question context should
- // not be considered course tags.
- $this->assertEmpty($question->coursetagobjects);
- $this->assertEmpty($question->coursetags);
-
- $actualtagobjects = $question->tagobjects;
- sort($tags);
- sort($actualtagobjects);
- // The tags should be considered question tags not course tags.
- $this->assertEquals($tags, $actualtagobjects);
- }
- }
-
- /**
- * get_question_options should return tags from all course contexts by default.
- */
- public function test_get_question_options_includes_multiple_courses_tags(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category');
- $question1 = $questions[0];
- $question2 = $questions[1];
- $coursecontext = \context_course::instance($course->id);
- // Create a sibling course.
- $siblingcourse = $this->getDataGenerator()->create_course(['category' => $course->category]);
- $siblingcoursecontext = \context_course::instance($siblingcourse->id);
-
- // Create course tags.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['c1']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['c1']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $siblingcoursecontext, ['c2']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $siblingcoursecontext, ['c2']);
-
- get_question_options($questions, true);
-
- foreach ($questions as $question) {
- $this->assertCount(2, $question->coursetagobjects);
-
- foreach ($question->coursetagobjects as $tag) {
- if ($tag->name == 'c1') {
- $this->assertEquals($coursecontext->id, $tag->taginstancecontextid);
- } else {
- $this->assertEquals($siblingcoursecontext->id, $tag->taginstancecontextid);
- }
- }
- }
- }
-
- /**
- * get_question_options should filter the course tags by the given list of courses.
- */
- public function test_get_question_options_includes_filter_course_tags(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category');
- $question1 = $questions[0];
- $question2 = $questions[1];
- $coursecontext = \context_course::instance($course->id);
- // Create a sibling course.
- $siblingcourse = $this->getDataGenerator()->create_course(['category' => $course->category]);
- $siblingcoursecontext = \context_course::instance($siblingcourse->id);
-
- // Create course tags.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['foo']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['bar']);
- // Create sibling course tags. These should be filtered out.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $siblingcoursecontext, ['filtered1']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $siblingcoursecontext, ['filtered2']);
-
- // Ask to only receive course tags from $course (ignoring $siblingcourse tags).
- get_question_options($questions, true, [$course]);
-
- foreach ($questions as $question) {
- foreach ($question->coursetagobjects as $tag) {
- // We should only be seeing course tags from $course. The tags from
- // $siblingcourse should have been filtered out.
- $this->assertEquals($coursecontext->id, $tag->taginstancecontextid);
- }
- }
- }
-
- /**
- * question_move_question_tags_to_new_context should update all of the
- * question tags contexts when they are moving down (from system to course
- * category context).
- */
- public function test_question_move_question_tags_to_new_context_system_to_course_cat_qtags(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('system');
- $question1 = $questions[0];
- $question2 = $questions[1];
- $qcontext = \context::instance_by_id($qcat->contextid);
- $newcontext = \context_coursecat::instance($category->id);
-
- foreach ($questions as $question) {
- $question->contextid = $qcat->contextid;
- }
-
- // Create tags in the system context.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo', 'bar']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo', 'bar']);
-
- question_move_question_tags_to_new_context($questions, $newcontext);
-
- foreach ($questions as $question) {
- $tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
-
- // All of the tags should have their context id set to the new context.
- foreach ($tags as $tag) {
- $this->assertEquals($newcontext->id, $tag->taginstancecontextid);
- }
- }
- }
-
- /**
- * question_move_question_tags_to_new_context should update all of the question tags
- * contexts when they are moving down (from system to course category context)
- * but leave any tags in the course context where they are.
- */
- public function test_question_move_question_tags_to_new_context_system_to_course_cat_qtags_and_course_tags(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('system');
- $question1 = $questions[0];
- $question2 = $questions[1];
- $qcontext = \context::instance_by_id($qcat->contextid);
- $coursecontext = \context_course::instance($course->id);
- $newcontext = \context_coursecat::instance($category->id);
-
- foreach ($questions as $question) {
- $question->contextid = $qcat->contextid;
- }
-
- // Create tags in the system context.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']);
- // Create tags in the course context.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['ctag']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['ctag']);
-
- question_move_question_tags_to_new_context($questions, $newcontext);
-
- foreach ($questions as $question) {
- $tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
-
- foreach ($tags as $tag) {
- if ($tag->name == 'ctag') {
- // Course tags should remain in the course context.
- $this->assertEquals($coursecontext->id, $tag->taginstancecontextid);
- } else {
- // Other tags should be updated.
- $this->assertEquals($newcontext->id, $tag->taginstancecontextid);
- }
- }
- }
- }
-
- /**
- * question_move_question_tags_to_new_context should update all of the question
- * contexts tags when they are moving up (from course category to system context).
- */
- public function test_question_move_question_tags_to_new_context_course_cat_to_system_qtags(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category');
- $question1 = $questions[0];
- $question2 = $questions[1];
- $qcontext = \context::instance_by_id($qcat->contextid);
- $newcontext = \context_system::instance();
-
- foreach ($questions as $question) {
- $question->contextid = $qcat->contextid;
- }
-
- // Create tags in the course category context.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo', 'bar']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo', 'bar']);
-
- question_move_question_tags_to_new_context($questions, $newcontext);
-
- foreach ($questions as $question) {
- $tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
-
- // All of the tags should have their context id set to the new context.
- foreach ($tags as $tag) {
- $this->assertEquals($newcontext->id, $tag->taginstancecontextid);
- }
- }
- }
-
- /**
- * question_move_question_tags_to_new_context should update all of the question
- * tags contexts when they are moving up (from course category context to system
- * context) but leave any tags in the course context where they are.
- */
- public function test_question_move_question_tags_to_new_context_course_cat_to_system_qtags_and_course_tags(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category');
- $question1 = $questions[0];
- $question2 = $questions[1];
- $qcontext = \context::instance_by_id($qcat->contextid);
- $coursecontext = \context_course::instance($course->id);
- $newcontext = \context_system::instance();
-
- foreach ($questions as $question) {
- $question->contextid = $qcat->contextid;
- }
-
- // Create tags in the system context.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']);
- // Create tags in the course context.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['ctag']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['ctag']);
-
- question_move_question_tags_to_new_context($questions, $newcontext);
-
- foreach ($questions as $question) {
- $tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
-
- foreach ($tags as $tag) {
- if ($tag->name == 'ctag') {
- // Course tags should remain in the course context.
- $this->assertEquals($coursecontext->id, $tag->taginstancecontextid);
- } else {
- // Other tags should be updated.
- $this->assertEquals($newcontext->id, $tag->taginstancecontextid);
- }
- }
- }
- }
-
- /**
- * question_move_question_tags_to_new_context should merge all tags into the course
- * context when moving down from course category context into course context.
- */
- public function test_question_move_question_tags_to_new_context_course_cat_to_coures_qtags_and_course_tags(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category');
- $question1 = $questions[0];
- $question2 = $questions[1];
- $qcontext = \context::instance_by_id($qcat->contextid);
- $coursecontext = \context_course::instance($course->id);
- $newcontext = $coursecontext;
-
- foreach ($questions as $question) {
- $question->contextid = $qcat->contextid;
- }
-
- // Create tags in the system context.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']);
- // Create tags in the course context.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['ctag']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['ctag']);
-
- question_move_question_tags_to_new_context($questions, $newcontext);
-
- foreach ($questions as $question) {
- $tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
- // Each question should have 2 tags.
- $this->assertCount(2, $tags);
-
- foreach ($tags as $tag) {
- // All tags should be updated to the course context and merged in.
- $this->assertEquals($newcontext->id, $tag->taginstancecontextid);
- }
- }
- }
-
- /**
- * question_move_question_tags_to_new_context should delete all of the tag
- * instances from sibling courses when moving the context of a question down
- * from a course category into a course context because the other courses will
- * no longer have access to the question.
- */
- public function test_question_move_question_tags_to_new_context_remove_other_course_tags(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category');
- // Create a sibling course.
- $siblingcourse = $this->getDataGenerator()->create_course(['category' => $course->category]);
- $question1 = $questions[0];
- $question2 = $questions[1];
- $qcontext = \context::instance_by_id($qcat->contextid);
- $coursecontext = \context_course::instance($course->id);
- $siblingcoursecontext = \context_course::instance($siblingcourse->id);
- $newcontext = $coursecontext;
-
- foreach ($questions as $question) {
- $question->contextid = $qcat->contextid;
- }
-
- // Create tags in the system context.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']);
- // Create tags in the target course context.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['ctag']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['ctag']);
- // Create tags in the sibling course context. These should be deleted as
- // part of the move.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $siblingcoursecontext, ['stag']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $siblingcoursecontext, ['stag']);
-
- question_move_question_tags_to_new_context($questions, $newcontext);
-
- foreach ($questions as $question) {
- $tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
- // Each question should have 2 tags, 'foo' and 'ctag'.
- $this->assertCount(2, $tags);
-
- foreach ($tags as $tag) {
- $tagname = $tag->name;
- // The 'stag' should have been deleted because it's in a sibling
- // course context.
- $this->assertContains($tagname, ['foo', 'ctag']);
- // All tags should be in the course context now.
- $this->assertEquals($coursecontext->id, $tag->taginstancecontextid);
- }
- }
- }
-
- /**
- * question_move_question_tags_to_new_context should update all of the question
- * tags to be the course category context when moving the tags from a course
- * context to a course category context.
- */
- public function test_question_move_question_tags_to_new_context_course_to_course_cat(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('course');
- $question1 = $questions[0];
- $question2 = $questions[1];
- $qcontext = \context::instance_by_id($qcat->contextid);
- // Moving up into the course category context.
- $newcontext = \context_coursecat::instance($category->id);
-
- foreach ($questions as $question) {
- $question->contextid = $qcat->contextid;
- }
-
- // Create tags in the course context.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']);
-
- question_move_question_tags_to_new_context($questions, $newcontext);
-
- foreach ($questions as $question) {
- $tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
-
- // All of the tags should have their context id set to the new context.
- foreach ($tags as $tag) {
- $this->assertEquals($newcontext->id, $tag->taginstancecontextid);
- }
- }
- }
-
- /**
- * question_move_question_tags_to_new_context should update all of the
- * question tags contexts when they are moving down (from system to course
- * category context).
- */
- public function test_question_move_question_tags_to_new_context_orphaned_tag_contexts(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('system');
- $question1 = $questions[0];
- $question2 = $questions[1];
- $othercategory = $this->getDataGenerator()->create_category();
- $qcontext = \context::instance_by_id($qcat->contextid);
- $newcontext = \context_coursecat::instance($category->id);
- $othercategorycontext = \context_coursecat::instance($othercategory->id);
-
- foreach ($questions as $question) {
- $question->contextid = $qcat->contextid;
- }
-
- // Create tags in the system context.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']);
- // Create tags in the other course category context. These should be
- // update to the next context id because they represent erroneous data
- // from a time before context id was mandatory in the tag API.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $othercategorycontext, ['bar']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $othercategorycontext, ['bar']);
-
- question_move_question_tags_to_new_context($questions, $newcontext);
-
- foreach ($questions as $question) {
- $tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
- // Each question should have two tags, 'foo' and 'bar'.
- $this->assertCount(2, $tags);
-
- // All of the tags should have their context id set to the new context
- // (course category context).
- foreach ($tags as $tag) {
- $this->assertEquals($newcontext->id, $tag->taginstancecontextid);
- }
- }
- }
-
- /**
- * When moving from a course category context down into an activity context
- * all question context tags and course tags (where the course is a parent of
- * the activity) should move into the new context.
- */
- public function test_question_move_question_tags_to_new_context_course_cat_to_activity_qtags_and_course_tags(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category');
- $question1 = $questions[0];
- $question2 = $questions[1];
- $qcontext = \context::instance_by_id($qcat->contextid);
- $coursecontext = \context_course::instance($course->id);
- $newcontext = \context_module::instance($quiz->cmid);
-
- foreach ($questions as $question) {
- $question->contextid = $qcat->contextid;
- }
-
- // Create tags in the course category context.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']);
- // Move the questions to the activity context which is a child context of
- // $coursecontext.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['ctag']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['ctag']);
-
- question_move_question_tags_to_new_context($questions, $newcontext);
-
- foreach ($questions as $question) {
- $tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
- // Each question should have 2 tags.
- $this->assertCount(2, $tags);
-
- foreach ($tags as $tag) {
- $this->assertEquals($newcontext->id, $tag->taginstancecontextid);
- }
- }
- }
-
- /**
- * When moving from a course category context down into an activity context
- * all question context tags and course tags (where the course is a parent of
- * the activity) should move into the new context. Tags in course contexts
- * that are not a parent of the activity context should be deleted.
- */
- public function test_question_move_question_tags_to_new_context_course_cat_to_activity_orphaned_tags(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category');
- $question1 = $questions[0];
- $question2 = $questions[1];
- $qcontext = \context::instance_by_id($qcat->contextid);
- $coursecontext = \context_course::instance($course->id);
- $newcontext = \context_module::instance($quiz->cmid);
- $othercourse = $this->getDataGenerator()->create_course();
- $othercoursecontext = \context_course::instance($othercourse->id);
-
- foreach ($questions as $question) {
- $question->contextid = $qcat->contextid;
- }
-
- // Create tags in the course category context.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']);
- // Create tags in the course context.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['ctag']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['ctag']);
- // Create tags in the other course context. These should be deleted.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $othercoursecontext, ['delete']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $othercoursecontext, ['delete']);
-
- // Move the questions to the activity context which is a child context of
- // $coursecontext.
- question_move_question_tags_to_new_context($questions, $newcontext);
-
- foreach ($questions as $question) {
- $tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
- // Each question should have 2 tags.
- $this->assertCount(2, $tags);
-
- foreach ($tags as $tag) {
- // Make sure we don't have any 'delete' tags.
- $this->assertContains($tag->name, ['foo', 'ctag']);
- $this->assertEquals($newcontext->id, $tag->taginstancecontextid);
- }
- }
- }
-
- /**
- * When moving from a course context down into an activity context all of the
- * course tags should move into the activity context.
- */
- public function test_question_move_question_tags_to_new_context_course_to_activity_qtags(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('course');
- $question1 = $questions[0];
- $question2 = $questions[1];
- $qcontext = \context::instance_by_id($qcat->contextid);
- $newcontext = \context_module::instance($quiz->cmid);
-
- foreach ($questions as $question) {
- $question->contextid = $qcat->contextid;
- }
-
- // Create tags in the course context.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']);
-
- question_move_question_tags_to_new_context($questions, $newcontext);
-
- foreach ($questions as $question) {
- $tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
-
- foreach ($tags as $tag) {
- $this->assertEquals($newcontext->id, $tag->taginstancecontextid);
- }
- }
- }
-
- /**
- * When moving from a course context down into an activity context all of the
- * course tags should move into the activity context.
- */
- public function test_question_move_question_tags_to_new_context_activity_to_course_qtags(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions();
- $question1 = $questions[0];
- $question2 = $questions[1];
- $qcontext = \context::instance_by_id($qcat->contextid);
- $newcontext = \context_course::instance($course->id);
-
- foreach ($questions as $question) {
- $question->contextid = $qcat->contextid;
- }
-
- // Create tags in the activity context.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']);
-
- question_move_question_tags_to_new_context($questions, $newcontext);
-
- foreach ($questions as $question) {
- $tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
-
- foreach ($tags as $tag) {
- $this->assertEquals($newcontext->id, $tag->taginstancecontextid);
- }
- }
- }
-
- /**
- * question_move_question_tags_to_new_context should update all of the
- * question tags contexts when they are moving down (from system to course
- * category context).
+ * When moving all tags from one activity context into another activity context.
*
- * Course tags within the new category context should remain while any course
- * tags in course contexts that can no longer access the question should be
- * deleted.
+ * @covers ::question_move_question_tags_to_new_context()
*/
- public function test_question_move_question_tags_to_new_context_system_to_course_cat_with_orphaned_tags(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('system');
+ public function test_question_move_question_tags_to_new_context_activity_to_activity_qtags(): void {
+ [$category, $course, $quiz, $qcat, $questions] = $this->setup_quiz_and_questions();
+ $qbank = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
$question1 = $questions[0];
$question2 = $questions[1];
- $othercategory = $this->getDataGenerator()->create_category();
- $othercourse = $this->getDataGenerator()->create_course(['category' => $othercategory->id]);
$qcontext = \context::instance_by_id($qcat->contextid);
- $newcontext = \context_coursecat::instance($category->id);
- $othercategorycontext = \context_coursecat::instance($othercategory->id);
- $coursecontext = \context_course::instance($course->id);
- $othercoursecontext = \context_course::instance($othercourse->id);
+ $newcontext = \context_module::instance($qbank->cmid);
foreach ($questions as $question) {
$question->contextid = $qcat->contextid;
}
- // Create tags in the system context.
+ // Create tags in the quiz context.
\core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']);
\core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']);
- // Create tags in the child course context of the new context.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['bar']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['bar']);
- // Create tags in the other course context. These should be deleted when
- // the question moves to the new course category context because this
- // course belongs to a different category, which means it will no longer
- // have access to the question.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $othercoursecontext, ['delete']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $othercoursecontext, ['delete']);
question_move_question_tags_to_new_context($questions, $newcontext);
foreach ($questions as $question) {
$tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
- // Each question should have two tags, 'foo' and 'bar'.
- $this->assertCount(2, $tags);
- // All of the tags should have their context id set to the new context
- // (course category context).
foreach ($tags as $tag) {
- $this->assertContains($tag->name, ['foo', 'bar']);
-
- if ($tag->name == 'foo') {
- $this->assertEquals($newcontext->id, $tag->taginstancecontextid);
- } else {
- $this->assertEquals($coursecontext->id, $tag->taginstancecontextid);
- }
+ $this->assertEquals($newcontext->id, $tag->taginstancecontextid);
}
}
}
@@ -1391,7 +620,7 @@ class questionlib_test extends \advanced_testcase {
*/
public function test_question_sort_tags_includes_question_tags(): void {
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category');
+ [$category, $course, $quiz, $qcat, $questions] = $this->setup_quiz_and_questions();
$question1 = $questions[0];
$question2 = $questions[1];
$qcontext = \context::instance_by_id($qcat->contextid);
@@ -1419,115 +648,6 @@ class questionlib_test extends \advanced_testcase {
// The question should have a full set of each tag object.
$this->assertEquals($tags, $actualtagobjects);
- // The question should not have any course tags.
- $this->assertEmpty($tagobjects->coursetagobjects);
- }
- }
-
- /**
- * question_sort_tags() includes course tags for all questions in the list.
- */
- public function test_question_sort_tags_includes_question_course_tags(): void {
- global $DB;
-
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category');
- $question1 = $questions[0];
- $question2 = $questions[1];
- $coursecontext = \context_course::instance($course->id);
-
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['foo', 'bar']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['baz', 'bop']);
-
- foreach ($questions as $question) {
- $tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
- $tagobjects = question_sort_tags($tags, $qcat);
-
- $expectedtags = [];
- $actualtags = $tagobjects->coursetags;
- foreach ($actualtags as $coursetagid => $coursetagname) {
- $expectedtags[$coursetagid] = $coursetagname;
- }
-
- // The question should have a tags property populated with each tag id
- // and display name as a key vale pair.
- $this->assertEquals($expectedtags, $actualtags);
-
- $actualtagobjects = $tagobjects->coursetagobjects;
- sort($tags);
- sort($actualtagobjects);
-
- // The question should have a full set of each tag object.
- $this->assertEquals($tags, $actualtagobjects);
- // The question should not have any course tags.
- $this->assertEmpty($tagobjects->tagobjects);
- }
- }
-
- /**
- * question_sort_tags() should return tags from all course contexts by default.
- */
- public function test_question_sort_tags_includes_multiple_courses_tags(): void {
- global $DB;
-
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category');
- $question1 = $questions[0];
- $question2 = $questions[1];
- $coursecontext = \context_course::instance($course->id);
- // Create a sibling course.
- $siblingcourse = $this->getDataGenerator()->create_course(['category' => $course->category]);
- $siblingcoursecontext = \context_course::instance($siblingcourse->id);
-
- // Create course tags.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['c1']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['c1']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $siblingcoursecontext, ['c2']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $siblingcoursecontext, ['c2']);
-
- foreach ($questions as $question) {
- $tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
- $tagobjects = question_sort_tags($tags, $qcat);
- $this->assertCount(2, $tagobjects->coursetagobjects);
-
- foreach ($tagobjects->coursetagobjects as $tag) {
- if ($tag->name == 'c1') {
- $this->assertEquals($coursecontext->id, $tag->taginstancecontextid);
- } else {
- $this->assertEquals($siblingcoursecontext->id, $tag->taginstancecontextid);
- }
- }
- }
- }
-
- /**
- * question_sort_tags() should filter the course tags by the given list of courses.
- */
- public function test_question_sort_tags_includes_filter_course_tags(): void {
- global $DB;
-
- list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category');
- $question1 = $questions[0];
- $question2 = $questions[1];
- $coursecontext = \context_course::instance($course->id);
- // Create a sibling course.
- $siblingcourse = $this->getDataGenerator()->create_course(['category' => $course->category]);
- $siblingcoursecontext = \context_course::instance($siblingcourse->id);
-
- // Create course tags.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['foo']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['bar']);
- // Create sibling course tags. These should be filtered out.
- \core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $siblingcoursecontext, ['filtered1']);
- \core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $siblingcoursecontext, ['filtered2']);
-
- foreach ($questions as $question) {
- $tags = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
- $tagobjects = question_sort_tags($tags, $qcat, [$course]);
- foreach ($tagobjects->coursetagobjects as $tag) {
-
- // We should only be seeing course tags from $course. The tags from
- // $siblingcourse should have been filtered out.
- $this->assertEquals($coursecontext->id, $tag->taginstancecontextid);
- }
}
}
@@ -1664,8 +784,7 @@ class questionlib_test extends \advanced_testcase {
/** @var \core_question_generator $questiongenerator */
$questiongenerator = $generator->get_plugin_generator('core_question');
- $category = $generator->create_category();
- $context = \context_coursecat::instance($category->id);
+ $context = $this->create_course_and_question_bank();
$questioncat = $questiongenerator->create_question_category([
'contextid' => $context->id,
]);
@@ -1748,8 +867,7 @@ class questionlib_test extends \advanced_testcase {
$user = $generator->create_user();
$otheruser = $generator->create_user();
$roleid = $generator->create_role();
- $category = $generator->create_category();
- $context = \context_coursecat::instance($category->id);
+ $context = $this->create_course_and_question_bank();
$questioncat = $questiongenerator->create_question_category([
'contextid' => $context->id,
]);
@@ -1795,8 +913,7 @@ class questionlib_test extends \advanced_testcase {
$user = $generator->create_user();
$otheruser = $generator->create_user();
$roleid = $generator->create_role();
- $category = $generator->create_category();
- $context = \context_coursecat::instance($category->id);
+ $context = $this->create_course_and_question_bank();
$questioncat = $questiongenerator->create_question_category([
'contextid' => $context->id,
]);
@@ -1842,8 +959,7 @@ class questionlib_test extends \advanced_testcase {
$user = $generator->create_user();
$otheruser = $generator->create_user();
$roleid = $generator->create_role();
- $category = $generator->create_category();
- $context = \context_coursecat::instance($category->id);
+ $context = $this->create_course_and_question_bank();
$questioncat = $questiongenerator->create_question_category([
'contextid' => $context->id,
]);
@@ -1889,14 +1005,14 @@ class questionlib_test extends \advanced_testcase {
$user = $generator->create_user();
$otheruser = $generator->create_user();
$roleid = $generator->create_role();
- $category = $generator->create_category();
- $context = \context_coursecat::instance($category->id);
+ $context = $this->create_course_and_question_bank();
+ $coursecontext = $context->get_course_context();
$questioncat = $questiongenerator->create_question_category([
'contextid' => $context->id,
]);
- $newcategory = $generator->create_category();
- $newcontext = \context_coursecat::instance($newcategory->id);
+ $qbank2 = $generator->create_module('qbank', ['course' => $coursecontext->instanceid]);
+ $newcontext = \context_module::instance($qbank2->cmid);
$newquestioncat = $questiongenerator->create_question_category([
'contextid' => $newcontext->id,
]);
@@ -1946,8 +1062,7 @@ class questionlib_test extends \advanced_testcase {
$user = $generator->create_user();
$otheruser = $generator->create_user();
$roleid = $generator->create_role();
- $category = $generator->create_category();
- $context = \context_coursecat::instance($category->id);
+ $context = $this->create_course_and_question_bank();
$questioncat = $questiongenerator->create_question_category([
'contextid' => $context->id,
]);
@@ -1982,8 +1097,7 @@ class questionlib_test extends \advanced_testcase {
$questiongenerator = $generator->get_plugin_generator('core_question');
$user = $generator->create_user();
- $category = $generator->create_category();
- $context = \context_coursecat::instance($category->id);
+ $context = $this->create_course_and_question_bank();
$questioncat = $questiongenerator->create_question_category([
'contextid' => $context->id,
]);
@@ -2060,10 +1174,9 @@ class questionlib_test extends \advanced_testcase {
/** @var \core_question_generator $questiongenerator */
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
// Create a Course.
- $course = $this->getDataGenerator()->create_course();
- $coursecontext = \context_course::instance($course->id);
+ $context = $this->create_course_and_question_bank();
- $top = question_get_top_category($coursecontext->id, true);
+ $top = question_get_top_category($context->id, true);
$cat1 = $questiongenerator->create_question_category(['parent' => $top->id]);
$sub11 = $questiongenerator->create_question_category(['parent' => $cat1->id]);
$sub12 = $questiongenerator->create_question_category(['parent' => $cat1->id]);
@@ -2094,16 +1207,18 @@ class questionlib_test extends \advanced_testcase {
// Create a category tree.
$course = $this->getDataGenerator()->create_course();
- $coursecontext = \context_course::instance($course->id);
+ $qbank1 = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
+ $bank1context = \context_module::instance($qbank1->cmid);
+ $qbank2 = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
/** @var \core_question_generator $questiongenerator */
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
- $context = \context_system::instance();
+ $wrongcontext = \context_module::instance($qbank2->cmid);
- $top = question_get_top_category($coursecontext->id, true);
+ $top = question_get_top_category($bank1context->id, true);
$cat1 = $questiongenerator->create_question_category(['parent' => $top->id]);
$sub11 = $questiongenerator->create_question_category(['parent' => $cat1->id]);
$sub12 = $questiongenerator->create_question_category(['parent' => $cat1->id]);
- $cat2 = $questiongenerator->create_question_category(['parent' => $top->id, 'contextid' => $context->id]);
+ $cat2 = $questiongenerator->create_question_category(['parent' => $top->id, 'contextid' => $wrongcontext->id]);
$sub22 = $questiongenerator->create_question_category(['parent' => $cat2->id]);
// Test - returned array has keys and values the same.
@@ -2122,8 +1237,7 @@ class questionlib_test extends \advanced_testcase {
$generator = $this->getDataGenerator();
/** @var \core_question_generator $questiongenerator */
$questiongenerator = $generator->get_plugin_generator('core_question');
- $category = $generator->create_category();
- $context = \context_coursecat::instance($category->id);
+ $context = $this->create_course_and_question_bank();
// Create a top category.
$cat0 = question_get_top_category($context->id, true);
// Add sub-categories.
@@ -2147,15 +1261,18 @@ class questionlib_test extends \advanced_testcase {
$generator = $this->getDataGenerator();
/** @var \core_question_generator $questiongenerator */
$questiongenerator = $generator->get_plugin_generator('core_question');
- $category = $generator->create_category();
- $context = \context_coursecat::instance($category->id);
+ $bank1context = $this->create_course_and_question_bank();
+ $coursecontext = $bank1context->get_course_context();
+ $qbank2 = self::getDataGenerator()->create_module('qbank', ['course' => $coursecontext->instanceid]);
+ $bank2context = \context_module::instance($qbank2->cmid);
+
// Create a top category.
- $cat0 = question_get_top_category($context->id, true);
+ $cat0 = question_get_top_category($bank1context->id, true);
// Add sub-categories - but in a different context.
$cat1 = $questiongenerator->create_question_category(
- ['parent' => $cat0->id, 'contextid' => \context_system::instance()->id]);
+ ['parent' => $cat0->id, 'contextid' => $bank2context->id]);
$cat2 = $questiongenerator->create_question_category(
- ['parent' => $cat1->id, 'contextid' => \context_system::instance()->id]);
+ ['parent' => $cat1->id, 'contextid' => $bank2context->id]);
// Test the 'get parents' function only returns categories in the same context.
$this->assertEquals([$cat1->id], question_categorylist_parents($cat2->id));
@@ -2311,7 +1428,7 @@ class questionlib_test extends \advanced_testcase {
global $DB;
$this->resetAfterTest();
// Setup.
- $context = \context_system::instance();
+ $context = $this->create_course_and_question_bank();
/** @var \core_question_generator $qgen */
$qgen = $this->getDataGenerator()->get_plugin_generator('core_question');
$qcat = $qgen->create_question_category(array('contextid' => $context->id));
@@ -2348,7 +1465,7 @@ class questionlib_test extends \advanced_testcase {
global $DB;
$this->resetAfterTest();
// Setup.
- $context = \context_system::instance();
+ $context = $this->create_course_and_question_bank();
/** @var \core_question_generator $qgen */
$qgen = $this->getDataGenerator()->get_plugin_generator('core_question');
$qcat = $qgen->create_question_category(array('contextid' => $context->id));
@@ -2378,7 +1495,7 @@ class questionlib_test extends \advanced_testcase {
global $DB;
$this->resetAfterTest();
// Setup.
- $context = \context_system::instance();
+ $context = $this->create_course_and_question_bank();
/** @var \core_question_generator $qgen */
$qgen = $this->getDataGenerator()->get_plugin_generator('core_question');
$qcat = $qgen->create_question_category(array('contextid' => $context->id));
@@ -2409,7 +1526,7 @@ class questionlib_test extends \advanced_testcase {
global $DB;
$this->resetAfterTest();
// Setup.
- $context = \context_system::instance();
+ $context = $this->create_course_and_question_bank();
/** @var \core_question_generator $qgen */
$qgen = $this->getDataGenerator()->get_plugin_generator('core_question');
$qcat = $qgen->create_question_category(array('contextid' => $context->id));
diff --git a/mod/quiz/classes/structure.php b/mod/quiz/classes/structure.php
index b6a8101b91c..2256fa60408 100644
--- a/mod/quiz/classes/structure.php
+++ b/mod/quiz/classes/structure.php
@@ -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.
diff --git a/mod/quiz/edit.php b/mod/quiz/edit.php
index 3353ebc615f..39deda908f3 100644
--- a/mod/quiz/edit.php
+++ b/mod/quiz/edit.php
@@ -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");
diff --git a/mod/quiz/editgrading.php b/mod/quiz/editgrading.php
index e3614720e2c..56b74b4a4c4 100644
--- a/mod/quiz/editgrading.php
+++ b/mod/quiz/editgrading.php
@@ -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');
diff --git a/mod/quiz/lang/en/deprecated.txt b/mod/quiz/lang/en/deprecated.txt
index 27bba327fa8..1cc78afe195 100644
--- a/mod/quiz/lang/en/deprecated.txt
+++ b/mod/quiz/lang/en/deprecated.txt
@@ -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
diff --git a/mod/quiz/lang/en/quiz.php b/mod/quiz/lang/en/quiz.php
index 63b75f7938a..657874f58c4 100644
--- a/mod/quiz/lang/en/quiz.php
+++ b/mod/quiz/lang/en/quiz.php
@@ -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';
diff --git a/mod/quiz/report/overview/tests/behat/regrading.feature b/mod/quiz/report/overview/tests/behat/regrading.feature
index 619b048b3af..4b6b1bfa0a7 100644
--- a/mod/quiz/report/overview/tests/behat/regrading.feature
+++ b/mod/quiz/report/overview/tests/behat/regrading.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/attempt_basic.feature b/mod/quiz/tests/behat/attempt_basic.feature
index 04ebd106617..2006cb8df9a 100644
--- a/mod/quiz/tests/behat/attempt_basic.feature
+++ b/mod/quiz/tests/behat/attempt_basic.feature
@@ -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 | |
diff --git a/mod/quiz/tests/behat/attempt_begin.feature b/mod/quiz/tests/behat/attempt_begin.feature
index 1b7508ae1a1..40216bc62a3 100644
--- a/mod/quiz/tests/behat/attempt_begin.feature
+++ b/mod/quiz/tests/behat/attempt_begin.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/attempt_multiple_grades.feature b/mod/quiz/tests/behat/attempt_multiple_grades.feature
index 3942adbda61..2e70c4e7aa5 100644
--- a/mod/quiz/tests/behat/attempt_multiple_grades.feature
+++ b/mod/quiz/tests/behat/attempt_multiple_grades.feature
@@ -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
diff --git a/mod/quiz/tests/behat/attempt_require_previous.feature b/mod/quiz/tests/behat/attempt_require_previous.feature
index cf715db3482..dde8c467332 100644
--- a/mod/quiz/tests/behat/attempt_require_previous.feature
+++ b/mod/quiz/tests/behat/attempt_require_previous.feature
@@ -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
diff --git a/mod/quiz/tests/behat/attempt_review_options.feature b/mod/quiz/tests/behat/attempt_review_options.feature
index 2b8c0dce980..86b079c29fa 100644
--- a/mod/quiz/tests/behat/attempt_review_options.feature
+++ b/mod/quiz/tests/behat/attempt_review_options.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/attempt_sequential.feature b/mod/quiz/tests/behat/attempt_sequential.feature
index 5f620c56d5b..10f9bd5e4e7 100644
--- a/mod/quiz/tests/behat/attempt_sequential.feature
+++ b/mod/quiz/tests/behat/attempt_sequential.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/behat_mod_quiz.php b/mod/quiz/tests/behat/behat_mod_quiz.php
index b7c02f28168..f1ce1f6b2e3 100644
--- a/mod/quiz/tests/behat/behat_mod_quiz.php
+++ b/mod/quiz/tests/behat/behat_mod_quiz.php
@@ -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 . '."');
diff --git a/mod/quiz/tests/behat/completion_condition_attempts_used.feature b/mod/quiz/tests/behat/completion_condition_attempts_used.feature
index 6e42450577d..0b22b50066a 100644
--- a/mod/quiz/tests/behat/completion_condition_attempts_used.feature
+++ b/mod/quiz/tests/behat/completion_condition_attempts_used.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/completion_manual.feature b/mod/quiz/tests/behat/completion_manual.feature
index d2f3e2c762b..14e06ba0051 100644
--- a/mod/quiz/tests/behat/completion_manual.feature
+++ b/mod/quiz/tests/behat/completion_manual.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/editing_add.feature b/mod/quiz/tests/behat/editing_add.feature
index 6603a5b3ccf..f65696e08d9 100644
--- a/mod/quiz/tests/behat/editing_add.feature
+++ b/mod/quiz/tests/behat/editing_add.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/editing_move_by_click.feature b/mod/quiz/tests/behat/editing_move_by_click.feature
index 7f838d6665b..45986af801e 100644
--- a/mod/quiz/tests/behat/editing_move_by_click.feature
+++ b/mod/quiz/tests/behat/editing_move_by_click.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/editing_multiple_grades.feature b/mod/quiz/tests/behat/editing_multiple_grades.feature
index 6c52da061c6..079b6040d9e 100644
--- a/mod/quiz/tests/behat/editing_multiple_grades.feature
+++ b/mod/quiz/tests/behat/editing_multiple_grades.feature
@@ -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
diff --git a/mod/quiz/tests/behat/editing_question_numbering.feature b/mod/quiz/tests/behat/editing_question_numbering.feature
index 03c8e81ad2e..f6d1a372bee 100644
--- a/mod/quiz/tests/behat/editing_question_numbering.feature
+++ b/mod/quiz/tests/behat/editing_question_numbering.feature
@@ -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 ... |
diff --git a/mod/quiz/tests/behat/editing_remove_multiple_questions.feature b/mod/quiz/tests/behat/editing_remove_multiple_questions.feature
index 7a87eafc1f4..0ee5bb119dd 100644
--- a/mod/quiz/tests/behat/editing_remove_multiple_questions.feature
+++ b/mod/quiz/tests/behat/editing_remove_multiple_questions.feature
@@ -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
diff --git a/mod/quiz/tests/behat/editing_remove_question.feature b/mod/quiz/tests/behat/editing_remove_question.feature
index 1ae73b6e90a..05091ed1369 100644
--- a/mod/quiz/tests/behat/editing_remove_question.feature
+++ b/mod/quiz/tests/behat/editing_remove_question.feature
@@ -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
diff --git a/mod/quiz/tests/behat/editing_require_previous.feature b/mod/quiz/tests/behat/editing_require_previous.feature
index 1774edc643b..a0c07568928 100644
--- a/mod/quiz/tests/behat/editing_require_previous.feature
+++ b/mod/quiz/tests/behat/editing_require_previous.feature
@@ -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
diff --git a/mod/quiz/tests/behat/editing_section_headings.feature b/mod/quiz/tests/behat/editing_section_headings.feature
index 2aa55e9b0ff..37ab09408f5 100644
--- a/mod/quiz/tests/behat/editing_section_headings.feature
+++ b/mod/quiz/tests/behat/editing_section_headings.feature
@@ -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
diff --git a/mod/quiz/tests/behat/editing_set_marks_no_attempts.feature b/mod/quiz/tests/behat/editing_set_marks_no_attempts.feature
index 5fcde062bee..1291409ebd7 100644
--- a/mod/quiz/tests/behat/editing_set_marks_no_attempts.feature
+++ b/mod/quiz/tests/behat/editing_set_marks_no_attempts.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/editing_switch_bank.feature b/mod/quiz/tests/behat/editing_switch_bank.feature
index bba10db2f04..8b66759862b 100644
--- a/mod/quiz/tests/behat/editing_switch_bank.feature
+++ b/mod/quiz/tests/behat/editing_switch_bank.feature
@@ -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
diff --git a/mod/quiz/tests/behat/feedback_on_override_mark.feature b/mod/quiz/tests/behat/feedback_on_override_mark.feature
index c2620cd659a..b94c5807c22 100644
--- a/mod/quiz/tests/behat/feedback_on_override_mark.feature
+++ b/mod/quiz/tests/behat/feedback_on_override_mark.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/flag_questions.feature b/mod/quiz/tests/behat/flag_questions.feature
index 7870e199aaa..aecdf6edee5 100644
--- a/mod/quiz/tests/behat/flag_questions.feature
+++ b/mod/quiz/tests/behat/flag_questions.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/group_mode.feature b/mod/quiz/tests/behat/group_mode.feature
index 21a2fbc82f9..db4faf585f4 100644
--- a/mod/quiz/tests/behat/group_mode.feature
+++ b/mod/quiz/tests/behat/group_mode.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/info_page.feature b/mod/quiz/tests/behat/info_page.feature
index 318f7768d99..fc95a17e183 100644
--- a/mod/quiz/tests/behat/info_page.feature
+++ b/mod/quiz/tests/behat/info_page.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/manually_mark_question.feature b/mod/quiz/tests/behat/manually_mark_question.feature
index 981b2d29715..9bbfccf554d 100644
--- a/mod/quiz/tests/behat/manually_mark_question.feature
+++ b/mod/quiz/tests/behat/manually_mark_question.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/preview.feature b/mod/quiz/tests/behat/preview.feature
index 3d6fdc495f2..5266f474802 100644
--- a/mod/quiz/tests/behat/preview.feature
+++ b/mod/quiz/tests/behat/preview.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/quiz_activity_availability.feature b/mod/quiz/tests/behat/quiz_activity_availability.feature
index bb07940006d..d6fe0f90a8d 100644
--- a/mod/quiz/tests/behat/quiz_activity_availability.feature
+++ b/mod/quiz/tests/behat/quiz_activity_availability.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/quiz_activity_certainty.feature b/mod/quiz/tests/behat/quiz_activity_certainty.feature
index c8de86c9560..c9a377ab7ce 100644
--- a/mod/quiz/tests/behat/quiz_activity_certainty.feature
+++ b/mod/quiz/tests/behat/quiz_activity_certainty.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/quiz_activity_completion.feature b/mod/quiz/tests/behat/quiz_activity_completion.feature
index f9047398d7e..2c52d187a2e 100644
--- a/mod/quiz/tests/behat/quiz_activity_completion.feature
+++ b/mod/quiz/tests/behat/quiz_activity_completion.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/quiz_activity_completion_locked.feature b/mod/quiz/tests/behat/quiz_activity_completion_locked.feature
index dd60560f310..7ea12aa7b53 100644
--- a/mod/quiz/tests/behat/quiz_activity_completion_locked.feature
+++ b/mod/quiz/tests/behat/quiz_activity_completion_locked.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/quiz_activity_completion_unlocked.feature b/mod/quiz/tests/behat/quiz_activity_completion_unlocked.feature
index 79943ed6094..69a11262d7c 100644
--- a/mod/quiz/tests/behat/quiz_activity_completion_unlocked.feature
+++ b/mod/quiz/tests/behat/quiz_activity_completion_unlocked.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/quiz_feedback.feature b/mod/quiz/tests/behat/quiz_feedback.feature
index e7f5af11ae3..ed4185780b1 100644
--- a/mod/quiz/tests/behat/quiz_feedback.feature
+++ b/mod/quiz/tests/behat/quiz_feedback.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/quiz_interactive_multiple_tries.feature b/mod/quiz/tests/behat/quiz_interactive_multiple_tries.feature
index ba6e923d26b..efcb5b4bc71 100644
--- a/mod/quiz/tests/behat/quiz_interactive_multiple_tries.feature
+++ b/mod/quiz/tests/behat/quiz_interactive_multiple_tries.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/quiz_question_versions.feature b/mod/quiz/tests/behat/quiz_question_versions.feature
index 739da2fca53..c8c22e35474 100644
--- a/mod/quiz/tests/behat/quiz_question_versions.feature
+++ b/mod/quiz/tests/behat/quiz_question_versions.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/quiz_reset.feature b/mod/quiz/tests/behat/quiz_reset.feature
index b70e6b48435..98fa9629e8f 100644
--- a/mod/quiz/tests/behat/quiz_reset.feature
+++ b/mod/quiz/tests/behat/quiz_reset.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/random_question.feature b/mod/quiz/tests/behat/random_question.feature
index ae5080fdd58..8474261d025 100644
--- a/mod/quiz/tests/behat/random_question.feature
+++ b/mod/quiz/tests/behat/random_question.feature
@@ -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:
diff --git a/mod/quiz/tests/behat/reattempt_quiz.feature b/mod/quiz/tests/behat/reattempt_quiz.feature
index 36cd2b3bcc9..929ff27166c 100644
--- a/mod/quiz/tests/behat/reattempt_quiz.feature
+++ b/mod/quiz/tests/behat/reattempt_quiz.feature
@@ -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 |
diff --git a/mod/quiz/tests/behat/settings_form_fields_disableif.feature b/mod/quiz/tests/behat/settings_form_fields_disableif.feature
index 059e912251d..cd4fadaba3d 100644
--- a/mod/quiz/tests/behat/settings_form_fields_disableif.feature
+++ b/mod/quiz/tests/behat/settings_form_fields_disableif.feature
@@ -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 |
diff --git a/mod/quiz/tests/quiz_question_restore_test.php b/mod/quiz/tests/quiz_question_restore_test.php
index ac115904704..67de8cdfb8c 100644
--- a/mod/quiz/tests/quiz_question_restore_test.php
+++ b/mod/quiz/tests/quiz_question_restore_test.php
@@ -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));
diff --git a/question/bank/columnsortorder/classes/column_manager.php b/question/bank/columnsortorder/classes/column_manager.php
index badd6cc24d7..7676d9bc449 100644
--- a/question/bank/columnsortorder/classes/column_manager.php
+++ b/question/bank/columnsortorder/classes/column_manager.php
@@ -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;
diff --git a/question/bank/columnsortorder/tests/behat/question_bank.feature b/question/bank/columnsortorder/tests/behat/question_bank.feature
index fed6ab56be4..7a7ccc0db09 100644
--- a/question/bank/columnsortorder/tests/behat/question_bank.feature
+++ b/question/bank/columnsortorder/tests/behat/question_bank.feature
@@ -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.
diff --git a/question/bank/columnsortorder/tests/column_manager_test.php b/question/bank/columnsortorder/tests/column_manager_test.php
index c1816bffe33..c6ddfc44db1 100644
--- a/question/bank/columnsortorder/tests/column_manager_test.php
+++ b/question/bank/columnsortorder/tests/column_manager_test.php
@@ -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;
}
diff --git a/question/bank/comment/tests/backup_test.php b/question/bank/comment/tests/backup_test.php
index f908e16979c..aecd0f1f007 100644
--- a/question/bank/comment/tests/backup_test.php
+++ b/question/bank/comment/tests/backup_test.php
@@ -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]);
diff --git a/question/bank/comment/tests/behat/question_comment.feature b/question/bank/comment/tests/behat/question_comment.feature
index 702e88df9e1..f5958879fbf 100644
--- a/question/bank/comment/tests/behat/question_comment.feature
+++ b/question/bank/comment/tests/behat/question_comment.feature
@@ -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 |
diff --git a/question/bank/comment/tests/behat/question_comment_column.feature b/question/bank/comment/tests/behat/question_comment_column.feature
index 74006caf219..243be8bd412 100644
--- a/question/bank/comment/tests/behat/question_comment_column.feature
+++ b/question/bank/comment/tests/behat/question_comment_column.feature
@@ -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 |
diff --git a/question/bank/comment/tests/lib_test.php b/question/bank/comment/tests/lib_test.php
index 5cad82bab9a..ebf28e72c65 100644
--- a/question/bank/comment/tests/lib_test.php
+++ b/question/bank/comment/tests/lib_test.php
@@ -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 = [
diff --git a/question/bank/customfields/tests/customfield_test.php b/question/bank/customfields/tests/customfield_test.php
index 962ba0c8f6a..6fbd52c4ba5 100644
--- a/question/bank/customfields/tests/customfield_test.php
+++ b/question/bank/customfields/tests/customfield_test.php
@@ -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]);
diff --git a/question/bank/customfields/tests/question_handler_test.php b/question/bank/customfields/tests/question_handler_test.php
index 9ebd0e559e8..e0f62f10af1 100644
--- a/question/bank/customfields/tests/question_handler_test.php
+++ b/question/bank/customfields/tests/question_handler_test.php
@@ -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);
diff --git a/question/bank/deletequestion/classes/delete_action.php b/question/bank/deletequestion/classes/delete_action.php
index b1fc73b5474..b98ad9cb528 100644
--- a/question/bank/deletequestion/classes/delete_action.php
+++ b/question/bank/deletequestion/classes/delete_action.php
@@ -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;
}
diff --git a/question/bank/deletequestion/delete.php b/question/bank/deletequestion/delete.php
index 396dda83f99..99e3566359d 100644
--- a/question/bank/deletequestion/delete.php
+++ b/question/bank/deletequestion/delete.php
@@ -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');
diff --git a/question/bank/deletequestion/tests/behat/delete_question_column.feature b/question/bank/deletequestion/tests/behat/delete_question_column.feature
index 2e09b09a464..9c36f6ae240 100644
--- a/question/bank/deletequestion/tests/behat/delete_question_column.feature
+++ b/question/bank/deletequestion/tests/behat/delete_question_column.feature
@@ -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"
diff --git a/question/bank/editquestion/addquestion.php b/question/bank/editquestion/addquestion.php
index 7b8502bab44..102cd916041 100644
--- a/question/bank/editquestion/addquestion.php
+++ b/question/bank/editquestion/addquestion.php
@@ -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');
diff --git a/question/bank/editquestion/classes/copy_action.php b/question/bank/editquestion/classes/copy_action.php
index 514e91005b3..5b7a3058b3e 100644
--- a/question/bank/editquestion/classes/copy_action.php
+++ b/question/bank/editquestion/classes/copy_action.php
@@ -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 {
diff --git a/question/bank/editquestion/classes/edit_action.php b/question/bank/editquestion/classes/edit_action.php
index d642e37ce0a..09155d1f245 100644
--- a/question/bank/editquestion/classes/edit_action.php
+++ b/question/bank/editquestion/classes/edit_action.php
@@ -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 {
diff --git a/question/bank/editquestion/question.php b/question/bank/editquestion/question.php
index ee2efa87487..dfade996968 100644
--- a/question/bank/editquestion/question.php
+++ b/question/bank/editquestion/question.php
@@ -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();
diff --git a/question/bank/editquestion/tests/behat/qbank_editquestion.feature b/question/bank/editquestion/tests/behat/qbank_editquestion.feature
index 7614c0989b7..13b6b939a73 100644
--- a/question/bank/editquestion/tests/behat/qbank_editquestion.feature
+++ b/question/bank/editquestion/tests/behat/qbank_editquestion.feature
@@ -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 |
diff --git a/question/bank/editquestion/tests/behat/question_status.feature b/question/bank/editquestion/tests/behat/question_status.feature
index 92fe44cfe12..a040c68d4d5 100644
--- a/question/bank/editquestion/tests/behat/question_status.feature
+++ b/question/bank/editquestion/tests/behat/question_status.feature
@@ -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 |
diff --git a/question/bank/exporttoxml/classes/helper.php b/question/bank/exporttoxml/classes/helper.php
index e2276992e73..431bc822d2c 100644
--- a/question/bank/exporttoxml/classes/helper.php
+++ b/question/bank/exporttoxml/classes/helper.php
@@ -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]
+ );
}
}
diff --git a/question/bank/exporttoxml/exportone.php b/question/bank/exporttoxml/exportone.php
index 6fc3cab8910..768873ad032 100644
--- a/question/bank/exporttoxml/exportone.php
+++ b/question/bank/exporttoxml/exportone.php
@@ -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.
diff --git a/question/bank/exporttoxml/tests/behat/export_to_xml_action.feature b/question/bank/exporttoxml/tests/behat/export_to_xml_action.feature
index 64ef39857c7..9185882cfee 100644
--- a/question/bank/exporttoxml/tests/behat/export_to_xml_action.feature
+++ b/question/bank/exporttoxml/tests/behat/export_to_xml_action.feature
@@ -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 |
diff --git a/question/bank/exporttoxml/tests/behat/preview_question.feature b/question/bank/exporttoxml/tests/behat/preview_question.feature
index 9420ecc64ee..72e88432c63 100644
--- a/question/bank/exporttoxml/tests/behat/preview_question.feature
+++ b/question/bank/exporttoxml/tests/behat/preview_question.feature
@@ -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 |
diff --git a/question/bank/history/classes/helper.php b/question/bank/history/classes/helper.php
index 58dd7563bb0..834c93b6eec 100644
--- a/question/bank/history/classes/helper.php
+++ b/question/bank/history/classes/helper.php
@@ -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);
+ }
+
}
diff --git a/question/bank/history/classes/history_action.php b/question/bank/history/classes/history_action.php
index 7157cf806d6..894712ab6f5 100644
--- a/question/bank/history/classes/history_action.php
+++ b/question/bank/history/classes/history_action.php
@@ -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];
diff --git a/question/bank/history/classes/question_history_view.php b/question/bank/history/classes/question_history_view.php
index 769de64b7c1..6931512a942 100644
--- a/question/bank/history/classes/question_history_view.php
+++ b/question/bank/history/classes/question_history_view.php
@@ -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);
diff --git a/question/bank/history/history.php b/question/bank/history/history.php
index 6e80d200765..9ad76f75255 100644
--- a/question/bank/history/history.php
+++ b/question/bank/history/history.php
@@ -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);
diff --git a/question/bank/history/tests/behat/question_history_action.feature b/question/bank/history/tests/behat/question_history_action.feature
index ac1ca5877f0..fd2f7bb0777 100644
--- a/question/bank/history/tests/behat/question_history_action.feature
+++ b/question/bank/history/tests/behat/question_history_action.feature
@@ -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 |
diff --git a/question/bank/history/tests/behat/question_version_column.feature b/question/bank/history/tests/behat/question_version_column.feature
index 81ddace0cb7..c18e2485252 100644
--- a/question/bank/history/tests/behat/question_version_column.feature
+++ b/question/bank/history/tests/behat/question_version_column.feature
@@ -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 |
diff --git a/question/bank/history/tests/helper_test.php b/question/bank/history/tests/helper_test.php
index 331423e0b1b..8bff1a7896b 100644
--- a/question/bank/history/tests/helper_test.php
+++ b/question/bank/history/tests/helper_test.php
@@ -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);
diff --git a/question/bank/history/tests/question_history_view_test.php b/question/bank/history/tests/question_history_view_test.php
index e33484ef25f..265fe283461 100644
--- a/question/bank/history/tests/question_history_view_test.php
+++ b/question/bank/history/tests/question_history_view_test.php
@@ -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();
diff --git a/question/bank/importquestions/import.php b/question/bank/importquestions/import.php
index dea5b4c2a7c..3d7c9340002 100644
--- a/question/bank/importquestions/import.php
+++ b/question/bank/importquestions/import.php
@@ -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);
}
diff --git a/question/bank/managecategories/category.php b/question/bank/managecategories/category.php
index 0f12841f68c..9afd4626867 100644
--- a/question/bank/managecategories/category.php
+++ b/question/bank/managecategories/category.php
@@ -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,
diff --git a/question/bank/managecategories/classes/category_condition.php b/question/bank/managecategories/classes/category_condition.php
index 6ff8882e556..a8d82c98a52 100644
--- a/question/bank/managecategories/classes/category_condition.php
+++ b/question/bank/managecategories/classes/category_condition.php
@@ -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;
diff --git a/question/bank/managecategories/classes/question_categories.php b/question/bank/managecategories/classes/question_categories.php
index 2a642a01fde..55e588818d7 100644
--- a/question/bank/managecategories/classes/question_categories.php
+++ b/question/bank/managecategories/classes/question_categories.php
@@ -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) {
diff --git a/question/bank/managecategories/classes/question_category_list_item.php b/question/bank/managecategories/classes/question_category_list_item.php
index 1f288a271a2..00d012add20 100644
--- a/question/bank/managecategories/classes/question_category_list_item.php
+++ b/question/bank/managecategories/classes/question_category_list_item.php
@@ -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]);
diff --git a/question/bank/managecategories/tests/behat/move_question_categories.feature b/question/bank/managecategories/tests/behat/move_question_categories.feature
index 1279686dceb..9e5c6aa43cc 100644
--- a/question/bank/managecategories/tests/behat/move_question_categories.feature
+++ b/question/bank/managecategories/tests/behat/move_question_categories.feature
@@ -11,9 +11,9 @@ Feature: A teacher can reorder question categories
And the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | weeks |
- And the following "categories" exist:
- | name | category | idnumber |
- | Category 1 | 0 | CAT1 |
+ 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 |
| teacher1 | C1 | editingteacher |
@@ -21,16 +21,15 @@ Feature: A teacher can reorder question categories
| user | role | contextlevel |
| teacher1 | editingteacher | System |
And the following "question categories" exist:
- | contextlevel | reference | name | idnumber |
- | Course | C1 | Course category 1 | questioncat1 |
- | Course | C1 | Course category 2 | questioncat2 |
- | Course | C1 | Course category 3 | questioncat3 |
- | Category | CAT1 | Default for Category 1 | |
- | System | S1 | System category | |
+ | contextlevel | reference | name | idnumber |
+ | Course | C1 | Course category 1 | questioncat1 |
+ | Course | C1 | Course category 2 | questioncat2 |
+ | Course | C1 | Course category 3 | questioncat3 |
And I am on the "Course 1" "core_question > course question categories" page logged in as "teacher1"
Scenario: Teacher cannot move or delete single category under context
- When I open the action menu in "Default for Category 1" "list_item"
+ Given I am on the "Qbank 1" "core_question > question categories" page logged in as "teacher1"
+ When I open the action menu in "Default for Qbank 1" "list_item"
Then I should not see "Delete"
Scenario: Teacher can see complete edit menu if multiples categories exist under context
@@ -67,35 +66,9 @@ Feature: A teacher can reorder question categories
And "Course category 3" "list_item" should appear before "Course category 2" "list_item"
And "Course category 3" "list_item" should exist in the "Course category 1" "list_item"
- Scenario: Teacher can move a category between contexts
- Given "Course: Course 1" "text" should appear before "Course category 1" "list_item"
- And "Category: Category 1" "text" should appear after "Course category 1" "list_item"
- And "Category: Category 1" "text" should appear before "Default for Category 1" "list_item"
- And "Course category 2" "list_item" should appear before "Course category 3" "list_item"
- When I open the action menu in "Course category 1" "list_item"
- And I choose "Move" in the open action menu
- And I click on "After Default for Category 1" "link" in the "Move Course category 1" "dialogue"
- Then "Course: Course 1" "text" should appear before "Course category 1" "list_item"
- And "Category: Category 1" "text" should appear before "Course category 1" "list_item"
- And "Default for Category 1" "list_item" should appear before "Course category 1" "list_item"
-
Scenario: Teacher can display and hide category descriptions
+ Given I am on the "Qbank 1" "core_question > question categories" page logged in as "teacher1"
When I click on "Show descriptions" "checkbox"
- Then I should see "The default category for questions shared in context 'Category 1'."
+ Then I should see "The default category for questions shared in context 'Qbank 1'."
And I click on "Show descriptions" "checkbox"
- And I should not see "The default category for questions shared in context 'Category 1'."
-
- Scenario: Teacher cannot create a duplicate idnumber within a context by moving a category
- Given "Course category 1" "list_item" should appear before "System category" "list_item"
- And I open the action menu in "Course category 1" "list_item"
- And I choose "Move" in the open action menu
- And I click on "After System category" "link" in the "Move Course category 1" "dialogue"
- Then "Course category 1" "list_item" should appear after "System category" "list_item"
- And I open the action menu in "Course category 2" "list_item"
- And I choose "Edit settings" in the open action menu
- And I set the field "ID number" to "questioncat1"
- And I click on "Save changes" "button" in the "Edit category" "dialogue"
- And I open the action menu in "Course category 2" "list_item"
- And I choose "Move" in the open action menu
- And I click on "After Course category 1" "link" in the "Move Course category 2" "dialogue"
- And I should see "ID number already in use. Change it to move or update category."
+ And I should not see "The default category for questions shared in context 'Qbank 1'."
diff --git a/question/bank/managecategories/tests/behat/question_categories.feature b/question/bank/managecategories/tests/behat/question_categories.feature
index d01caa7bdde..f0b0f830f8c 100644
--- a/question/bank/managecategories/tests/behat/question_categories.feature
+++ b/question/bank/managecategories/tests/behat/question_categories.feature
@@ -12,16 +12,19 @@ Feature: A teacher can put questions in categories in the question bank
| fullname | shortname | format |
| Course 1 | C1 | weeks |
And the following "course enrolments" exist:
- | user | course | role |
- | teacher1 | C1 | editingteacher |
+ | 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 | questioncategory | name | sortorder | desciption |
- | Course | C1 | Top | top | 0 | |
- | Course | C1 | top | Default for C1 | 0 | Description for default for C1 |
- | Course | C1 | Default for C1 | Subcategory | 0 | Description for Subcategory |
- | Course | C1 | Default for C1 | Another subcat | 1 | Description for Another subcat |
- | Course | C1 | top | Used category | 1 | |
- | Course | C1 | top | Default & testing | 2 | |
+ | contextlevel | reference | questioncategory | name |
+ | Activity module | qbank1 | Top | top |
+ | Activity module | qbank1 | top | Default for qbank1 |
+ | Activity module | qbank1 | Default for qbank1 | Subcategory |
+ | Activity module | qbank1 | Default for qbank1 | Another subcat |
+ | Activity module | qbank1 | top | Used category |
+ | Activity module | qbank1 | top | Default & testing |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Used category | essay | Test question to be moved | Write about whatever you want |
@@ -29,7 +32,7 @@ Feature: A teacher can put questions in categories in the question bank
And I log in as "teacher1"
Scenario: A new question category can be created
- When I am on the "Course 1" "core_question > course question categories" page
+ When I am on the "Qbank 1" "core_question > question categories" page
And I press "Add category"
And I set the following fields to these values:
| Name | 'Test' & 'display' |
@@ -47,14 +50,14 @@ Feature: A teacher can put questions in categories in the question bank
And the "Parent category" select box should contain "'Test' & 'display' [newcatidnumber]"
Scenario: A question category can be edited
- When I am on the "Course 1" "core_question > course question categories" page
+ When I am on the "Qbank 1" "core_question > question categories" page
# There have been bugs which only happened if a question category was not empty, so add a question.
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Subcategory | essay | Test question for renaming category | Write about whatever you want |
And I open the action menu in "Subcategory" "list_item"
And I choose "Edit settings" in the open action menu
- And the field "parent" matches value " Default for C1"
+ And the field "parent" matches value " Default for qbank1"
And I set the following fields to these values:
| Name | New name |
| Category info | I was edited |
@@ -64,32 +67,32 @@ Feature: A teacher can put questions in categories in the question bank
And I should see "I was edited"
Scenario: An empty question category can be deleted
- When I am on the "Course 1" "core_question > course question categories" page
+ When I am on the "Qbank 1" "core_question > question categories" page
And I open the action menu in "Subcategory" "list_item"
And I choose "Delete" in the open action menu
And I click on "Delete" "button" in the "Delete" "dialogue"
Then I should not see "Subcategory"
Scenario: An non-empty question category can be deleted if you move the contents elsewhere
- When I am on the "Course 1" "core_question > course question categories" page
+ When 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 "Delete" in the open action menu
And I click on "Delete" "button" in the "Delete" "dialogue"
And I should see "The category 'Used category' contains 1 questions"
- And I select "Default for C1" from the "Category" singleselect
+ And I select "Default for qbank1" from the "Category" singleselect
And I press "Save in category"
Then I should not see "Used category"
- And I should see "Default for C1"
- And I should see "(1)"
+ And I press "Add category"
+ And I should see "Default for qbank1 (1)"
@_file_upload
Scenario: Multi answer questions with their child questions can be moved to another category when the current category is deleted
- When I am on the "Course 1" "core_question > course question import" page
+ When I am on the "Qbank 1" "core_question > question import" page
And I set the field "id_format_xml" to "1"
And I upload "question/format/xml/tests/fixtures/multianswer.xml" file to "Import" filemanager
And I press "id_submitbutton"
And I press "Continue"
- 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 "Default for Test images in backup" "list_item"
And I choose "Delete" in the open action menu
And I click on "Delete" "button" in the ".modal-footer" "css_element"
@@ -101,8 +104,8 @@ Feature: A teacher can put questions in categories in the question bank
And I should see "Used category (2)"
Scenario: Filter questions by category and subcategories
- When I am on the "Course 1" "core_question > course question bank" page
- And I apply question bank filter "Category" with value "Default for C1"
+ When I am on the "Qbank 1" "core_question > question bank" page
+ And I apply question bank filter "Category" with value "Default for qbank1"
Then I should not see "Question 1"
When I set the field "Also show questions from subcategories" to "1"
And I click on "Apply filters" "button"
diff --git a/question/bank/managecategories/tests/behat/question_categories_idnumber.feature b/question/bank/managecategories/tests/behat/question_categories_idnumber.feature
index 2db6176742c..b38d4e6aef9 100644
--- a/question/bank/managecategories/tests/behat/question_categories_idnumber.feature
+++ b/question/bank/managecategories/tests/behat/question_categories_idnumber.feature
@@ -14,20 +14,23 @@ Feature: A teacher can put questions with idnumbers in categories with idnumbers
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 I log in as "teacher1"
And I am on "Course 1" course homepage
Scenario: A new question category can only be created with a unique idnumber for a context
# Note need to create the top category each time.
When the following "question categories" exist:
- | contextlevel | reference | questioncategory | name | idnumber |
- | Course | C1 | Top | top | |
- | Course | C1 | top | Used category | c1used |
- And I am on the "Course 1" "core_question > course question categories" page
+ | contextlevel | reference | questioncategory | name | idnumber |
+ | Activity module | qbank1 | Top | top | |
+ | Activity module | qbank1 | top | Used category | c1used |
+ And I am on the "Qbank 1" "core_question > question categories" page
And I press "Add category"
And I set the following fields to these values:
| Name | New cat |
- | Parent category | Top for Course 1 |
+ | Parent category | Top for Qbank 1 |
| Category info | Created as a test |
| ID number | c1used |
And I click on "Add category" "button" in the "Add category" "dialogue"
@@ -45,10 +48,10 @@ Feature: A teacher can put questions with idnumbers in categories with idnumbers
Scenario: A question category can be edited and saved without changing the idnumber
When the following "question categories" exist:
- | contextlevel | reference | questioncategory | name | idnumber |
- | Course | C1 | Top | top | |
- | Course | C1 | top | Used category | c1used |
- And I am on the "Course 1" "core_question > course question categories" page
+ | contextlevel | reference | questioncategory | name | idnumber |
+ | Activity module | qbank1 | Top | top | |
+ | Activity module | qbank1 | top | Used category | c1used |
+ And I am on the "Qbank 1" "core_question > question categories" page
Then I open the action menu in "Used category" "list_item"
And I choose "Edit settings" in the open action menu
And I click on "Save changes" "button" in the "Edit category" "dialogue"
diff --git a/question/bank/managecategories/tests/behat/view_manage_categories_plugin.feature b/question/bank/managecategories/tests/behat/view_manage_categories_plugin.feature
index 457108cf720..f827bb8f122 100644
--- a/question/bank/managecategories/tests/behat/view_manage_categories_plugin.feature
+++ b/question/bank/managecategories/tests/behat/view_manage_categories_plugin.feature
@@ -10,8 +10,8 @@ Feature: Use the qbank plugin manager page for managecategories
| 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 |
diff --git a/question/bank/managecategories/tests/external/move_category_test.php b/question/bank/managecategories/tests/external/move_category_test.php
index ea0b5ee1182..614caf71b55 100644
--- a/question/bank/managecategories/tests/external/move_category_test.php
+++ b/question/bank/managecategories/tests/external/move_category_test.php
@@ -17,7 +17,7 @@
namespace qbank_managecategories\external;
use context;
-use context_course;
+use context_module;
use moodle_url;
use qbank_managecategories\question_categories;
@@ -75,13 +75,14 @@ final class move_category_test extends \qbank_managecategories\manage_category_t
// Create context for question categories.
$course = $this->create_course();
- $context = context_course::instance($course->id);
+ $qbank = $this->create_qbank($course);
+ $context = context_module::instance($qbank->cmid);
$this->create_course_category();
// Question categories.
- $qcat1 = $this->create_question_category_for_a_course($course);
- $qcat2 = $this->create_question_category_for_a_course($course);
- $qcat3 = $this->create_question_category_for_a_course($course);
+ $qcat1 = $this->create_question_category_for_a_qbank($qbank);
+ $qcat2 = $this->create_question_category_for_a_qbank($qbank);
+ $qcat3 = $this->create_question_category_for_a_qbank($qbank);
// Check current order.
$currentorder = $this->get_current_order($context);
@@ -136,14 +137,14 @@ final class move_category_test extends \qbank_managecategories\manage_category_t
$this->resetAfterTest();
// Create context for question categories.
- $course = $this->create_course();
- $context = context_course::instance($course->id);
+ $qbank = $this->create_qbank($this->create_course());
+ $context = context_module::instance($qbank->cmid);
$this->create_course_category();
// Question categories.
- $qcat1 = $this->create_question_category_for_a_course($course);
- $qcat2 = $this->create_question_category_for_a_course($course);
- $qcat3 = $this->create_question_category_for_a_course($course);
+ $qcat1 = $this->create_question_category_for_a_qbank($qbank);
+ $qcat2 = $this->create_question_category_for_a_qbank($qbank);
+ $qcat3 = $this->create_question_category_for_a_qbank($qbank);
// Check current order.
$currentorder = $this->get_current_order($context);
@@ -205,14 +206,14 @@ final class move_category_test extends \qbank_managecategories\manage_category_t
$this->resetAfterTest();
// Create context for question categories.
- $course = $this->create_course();
- $context = context_course::instance($course->id);
+ $qbank = $this->create_qbank($this->create_course());
+ $context = context_module::instance($qbank->cmid);
$this->create_course_category();
// Question categories.
- $qcat1 = $this->create_question_category_for_a_course($course);
- $qcat2 = $this->create_question_category_for_a_course($course);
- $qcat3 = $this->create_question_category_for_a_course($course);
+ $qcat1 = $this->create_question_category_for_a_qbank($qbank);
+ $qcat2 = $this->create_question_category_for_a_qbank($qbank);
+ $qcat3 = $this->create_question_category_for_a_qbank($qbank);
// Check current order.
$currentorder = $this->get_current_order($context);
@@ -278,15 +279,15 @@ final class move_category_test extends \qbank_managecategories\manage_category_t
$this->resetAfterTest();
// Create context for question categories.
- $course = $this->create_course();
- $context = context_course::instance($course->id);
+ $qbank = $this->create_qbank($this->create_course());
+ $context = context_module::instance($qbank->cmid);
$this->create_course_category();
// Question categories.
- $qcat1 = $this->create_question_category_for_a_course($course);
- $qcat2 = $this->create_question_category_for_a_course($course);
- $qcat3 = $this->create_question_category_for_a_course($course, ['parent' => $qcat1->id]);
- $qcat4 = $this->create_question_category_for_a_course($course, ['parent' => $qcat2->id]);
+ $qcat1 = $this->create_question_category_for_a_qbank($qbank);
+ $qcat2 = $this->create_question_category_for_a_qbank($qbank);
+ $qcat3 = $this->create_question_category_for_a_qbank($qbank, ['parent' => $qcat1->id]);
+ $qcat4 = $this->create_question_category_for_a_qbank($qbank, ['parent' => $qcat2->id]);
// Check current order.
$currentorder = $this->get_current_order($context);
@@ -329,77 +330,6 @@ final class move_category_test extends \qbank_managecategories\manage_category_t
$this->assertEquals($stateupdates, $expectedstateupdates);
}
- /**
- * Move a category from the top category of one context to another.
- *
- * @return void
- */
- public function test_move_category_between_contexts(): void {
- $this->setAdminUser();
- $this->resetAfterTest();
-
- // Create context for question categories.
- $course = $this->create_course();
- $coursecontext = context_course::instance($course->id);
- $coursecategory = $this->create_course_category();
- $categorycontext = \context_coursecat::instance($coursecategory->id);
-
- // Question categories.
- $coursecatqcat = question_get_top_category($categorycontext->id, true);
- $qcat1 = $this->create_question_category_for_a_course($course);
- $qcat2 = $this->create_question_category_for_a_course($course);
-
- $currentcourseorder = $this->get_current_order($coursecontext);
- $expectedorder = [
- $qcat1->id => [],
- $qcat2->id => [],
- ];
- $this->assertEquals($expectedorder, $currentcourseorder);
- $currentcoursecatorder = $this->get_current_order($categorycontext);
- $expectedcoursecatorder = [
- ];
- $this->assertEquals($expectedcoursecatorder, $currentcoursecatorder);
-
- $stateupdates = move_category::execute($coursecontext->id, $qcat1->id, $coursecatqcat->id);
-
- $newcourseorder = $this->get_current_order($coursecontext);
- $newexpectedorder = [
- $qcat2->id => [],
- ];
- $this->assertEquals($newcourseorder, $newexpectedorder);
- $newcoursecatorder = $this->get_current_order($categorycontext);
- $newexpectedcoursecatorder = [
- $qcat1->id => [],
- ];
- $this->assertEquals($newcoursecatorder, $newexpectedcoursecatorder);
-
- // Expect an update to the sortorder, parent and context of the moved category.
- // Since the original sibling is the only remaining child of a top-level category, it has its draghandle property
- // updated as well as its sortorder.
- $expectedstateupdates = [
- (object)[
- 'name' => 'categories',
- 'action' => 'put',
- 'fields' => (object)[
- 'id' => $qcat1->id,
- 'sortorder' => 1,
- 'parent' => $coursecatqcat->id,
- 'context' => $categorycontext->id,
- ],
- ],
- (object)[
- 'name' => 'categories',
- 'action' => 'put',
- 'fields' => (object)[
- 'id' => $qcat2->id,
- 'sortorder' => 1,
- 'draghandle' => false,
- ],
- ],
- ];
- $this->assertEquals($stateupdates, $expectedstateupdates);
- }
-
/**
* Move a category that has its own children.
*
@@ -412,16 +342,16 @@ final class move_category_test extends \qbank_managecategories\manage_category_t
$this->resetAfterTest();
// Create context for question categories.
- $course = $this->create_course();
- $context = context_course::instance($course->id);
+ $qbank = $this->create_qbank($this->create_course());
+ $context = context_module::instance($qbank->cmid);
$this->create_course_category();
// Question categories.
- $qcat1 = $this->create_question_category_for_a_course($course);
- $qcat2 = $this->create_question_category_for_a_course($course);
- $qcat3 = $this->create_question_category_for_a_course($course);
- $qcat4 = $this->create_question_category_for_a_course($course, ['parent' => $qcat3->id]);
- $qcat5 = $this->create_question_category_for_a_course($course, ['parent' => $qcat3->id]);
+ $qcat1 = $this->create_question_category_for_a_qbank($qbank);
+ $qcat2 = $this->create_question_category_for_a_qbank($qbank);
+ $qcat3 = $this->create_question_category_for_a_qbank($qbank);
+ $qcat4 = $this->create_question_category_for_a_qbank($qbank, ['parent' => $qcat3->id]);
+ $qcat5 = $this->create_question_category_for_a_qbank($qbank, ['parent' => $qcat3->id]);
// Check current order.
$currentorder = $this->get_current_order($context);
@@ -482,16 +412,16 @@ final class move_category_test extends \qbank_managecategories\manage_category_t
$this->resetAfterTest();
// Create context for question categories.
- $course = $this->create_course();
- $context = context_course::instance($course->id);
+ $qbank = $this->create_qbank($this->create_course());
+ $context = context_module::instance($qbank->cmid);
$this->create_course_category();
// Question categories.
- $qcat1 = $this->create_question_category_for_a_course($course);
- $qcat2 = $this->create_question_category_for_a_course($course);
- $qcat3 = $this->create_question_category_for_a_course($course);
- $qcat4 = $this->create_question_category_for_a_course($course, ['parent' => $qcat3->id]);
- $qcat5 = $this->create_question_category_for_a_course($course, ['parent' => $qcat4->id]);
+ $qcat1 = $this->create_question_category_for_a_qbank($qbank);
+ $qcat2 = $this->create_question_category_for_a_qbank($qbank);
+ $qcat3 = $this->create_question_category_for_a_qbank($qbank);
+ $qcat4 = $this->create_question_category_for_a_qbank($qbank, ['parent' => $qcat3->id]);
+ $qcat5 = $this->create_question_category_for_a_qbank($qbank, ['parent' => $qcat4->id]);
// Check current order.
$currentorder = $this->get_current_order($context);
diff --git a/question/bank/managecategories/tests/helper_test.php b/question/bank/managecategories/tests/helper_test.php
index ed8be52e7ce..cb687f1175a 100644
--- a/question/bank/managecategories/tests/helper_test.php
+++ b/question/bank/managecategories/tests/helper_test.php
@@ -166,7 +166,7 @@ final class helper_test extends manage_category_test_base {
$qcategory1 = $this->qgenerator->create_question_category(['contextid' => $this->context->id]);
// Try to delete a top category.
- $categorytop = question_get_top_category($qcategory1->id, true)->id;
+ $categorytop = question_get_top_category($qcategory1->contextid, true)->id;
try {
helper::question_can_delete_cat($categorytop);
} catch (moodle_exception $e) {
diff --git a/question/bank/managecategories/tests/manage_category_test_base.php b/question/bank/managecategories/tests/manage_category_test_base.php
index 360dcfbd3ed..51219b148af 100644
--- a/question/bank/managecategories/tests/manage_category_test_base.php
+++ b/question/bank/managecategories/tests/manage_category_test_base.php
@@ -16,8 +16,6 @@
namespace qbank_managecategories;
-use core_question\local\bank\question_edit_contexts;
-use moodle_url;
/**
* Test base for category tests
*
@@ -39,17 +37,6 @@ abstract class manage_category_test_base extends \advanced_testcase {
return $questiongenerator->create_question_category($categorydetails);
}
- /**
- * Create a question category for the system.
- *
- * @param array $categorydetails details of the category
- * @return \stdClass question category record
- */
- protected function create_question_category_for_the_system(array $categorydetails = []): \stdClass {
- $context = \context_system::instance();
- return $this->create_new_question_category_for_a_context($context->id, $categorydetails);
- }
-
/**
* Create a course category
*
@@ -60,21 +47,6 @@ abstract class manage_category_test_base extends \advanced_testcase {
return $this->getDataGenerator()->create_category();
}
- /**
- * Create a question category for a course category.
- *
- * @param \core_course_category $coursecategory the course category that new question category will be created for
- * @param array $categorydetails details of the category
- * @return \stdClass question category record
- */
- protected function create_question_category_for_a_course_category(
- \core_course_category $coursecategory,
- array $categorydetails = [],
- ): \stdClass {
- $context = \context_coursecat::instance($coursecategory->id);
- return $this->create_new_question_category_for_a_context($context->id, $categorydetails);
- }
-
/**
* Create a course
*
@@ -86,14 +58,24 @@ abstract class manage_category_test_base extends \advanced_testcase {
}
/**
- * Create a question category for a course.
+ * Create a mod_qbank instance.
*
- * @param \stdClass $course the course that new question category will be created for
+ * @param \stdClass $course to add the mod_qbank instance to.
+ * @return \stdClass new qbank module
+ */
+ protected function create_qbank(\stdClass $course): \stdClass {
+ return self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
+ }
+
+ /**
+ * Create a question category for a qbank module.
+ *
+ * @param \stdClass $qbank the qbank module that new question category will be created for
* @param array $categorydetails details of the category
* @return \stdClass category record
*/
- protected function create_question_category_for_a_course(\stdClass $course, array $categorydetails = []): \stdClass {
- $context = \context_course::instance($course->id);
+ protected function create_question_category_for_a_qbank(\stdClass $qbank, array $categorydetails = []): \stdClass {
+ $context = \context_module::instance($qbank->cmid);
return $this->create_new_question_category_for_a_context($context->id, $categorydetails);
}
diff --git a/question/bank/managecategories/tests/question_categories_test.php b/question/bank/managecategories/tests/question_categories_test.php
index 03c6b23d783..8a2e64b314d 100644
--- a/question/bank/managecategories/tests/question_categories_test.php
+++ b/question/bank/managecategories/tests/question_categories_test.php
@@ -39,19 +39,19 @@ final class question_categories_test extends manage_category_test_base {
$this->resetAfterTest();
// Create question categories for a course.
- $course = $this->create_course();
- $qcat1 = $this->create_question_category_for_a_course($course);
- $qcat2 = $this->create_question_category_for_a_course($course, ['parent' => $qcat1->id]);
- $qcat3 = $this->create_question_category_for_a_course($course);
- $qcat4 = $this->create_question_category_for_a_course($course, ['parent' => $qcat2->id]);
- $coursecontext = \context_course::instance($course->id);
+ $qbank = $this->create_qbank($this->create_course());
+ $qcat1 = $this->create_question_category_for_a_qbank($qbank);
+ $qcat2 = $this->create_question_category_for_a_qbank($qbank, ['parent' => $qcat1->id]);
+ $qcat3 = $this->create_question_category_for_a_qbank($qbank);
+ $qcat4 = $this->create_question_category_for_a_qbank($qbank, ['parent' => $qcat2->id]);
+ $context = \context_module::instance($qbank->cmid);
// Create ordered tree.
$questioncategories = new question_categories(
new \moodle_url('/'),
- [$coursecontext],
+ [$context],
);
- $items = $questioncategories->editlists[$coursecontext->id]->items;
+ $items = $questioncategories->editlists[$context->id]->items;
// Two top categories (1 and 3) in the course.
$this->assertCount(2, $items);
diff --git a/question/bank/previewquestion/classes/helper.php b/question/bank/previewquestion/classes/helper.php
index 3b0849a428e..29f5e761ed1 100644
--- a/question/bank/previewquestion/classes/helper.php
+++ b/question/bank/previewquestion/classes/helper.php
@@ -101,7 +101,7 @@ class helper {
* @param int $questionid the question being previewed
* @param int $qubaid the id of the question usage for this preview
* @param question_preview_options $options the options in use
- * @param context $context context for the question preview
+ * @param context $context module context for the question preview
* @param moodle_url $returnurl url of the page to return to
* @param int|null $restartversion version of the question to use when next restarting the preview.
* @return moodle_url
@@ -112,11 +112,13 @@ class helper {
'id' => $questionid,
'previewid' => $qubaid,
];
- if ($context->contextlevel == CONTEXT_MODULE) {
- $params['cmid'] = $context->instanceid;
- } else if ($context->contextlevel == CONTEXT_COURSE) {
- $params['courseid'] = $context->instanceid;
+
+ if ($context->contextlevel !== CONTEXT_MODULE) {
+ debugging("Invalid contextlevel: {$context->contextlevel} must be CONTEXT_MODULE");
}
+
+ $params['cmid'] = $context->instanceid;
+
if ($returnurl !== null) {
$params['returnurl'] = $returnurl;
}
@@ -131,7 +133,7 @@ class helper {
* The the URL to use for actions relating to this preview.
*
* @param int $questionid the question being previewed
- * @param context $context the current moodle context
+ * @param context $context the current moodle module context
* @param int $previewid optional previewid to sign post saved previewed answers
* @param moodle_url $returnurl url of the page to return to
* @return moodle_url
@@ -140,11 +142,13 @@ class helper {
$params = [
'id' => $questionid,
];
- if ($context->contextlevel == CONTEXT_MODULE) {
- $params['cmid'] = $context->instanceid;
- } else if ($context->contextlevel == CONTEXT_COURSE) {
- $params['courseid'] = $context->instanceid;
+
+ if ($context->contextlevel !== CONTEXT_MODULE) {
+ debugging("Invalid contextlevel: {$context->contextlevel} must be CONTEXT_MODULE");
}
+
+ $params['cmid'] = $context->instanceid;
+
if ($previewid) {
$params['previewid'] = $previewid;
}
diff --git a/question/bank/previewquestion/preview.php b/question/bank/previewquestion/preview.php
index 2ee19639192..a7a9e10d8d5 100644
--- a/question/bank/previewquestion/preview.php
+++ b/question/bank/previewquestion/preview.php
@@ -63,11 +63,6 @@ if ($cmid = optional_param('cmid', 0, PARAM_INT)) {
$cm = get_coursemodule_from_id(false, $cmid);
require_login($cm->course, false, $cm);
$context = context_module::instance($cmid);
-
-} else if ($courseid = optional_param('courseid', 0, PARAM_INT)) {
- require_login($courseid);
- $context = context_course::instance($courseid);
-
} else {
require_login();
$category = $DB->get_record('question_categories', ['id' => $question->category], '*', MUST_EXIST);
@@ -321,7 +316,7 @@ if (!is_null($returnurl)) {
$previewdata['redirect'] = true;
$previewdata['redirecturl'] = $returnurl;
}
-$closeurl = new moodle_url('/question/edit.php', ['courseid' => $COURSE->id]);
+$closeurl = new moodle_url('/question/edit.php', ['cmid' => $context->instanceid]);
echo $PAGE->get_renderer('qbank_previewquestion')->render_preview_page($previewdata);
// Log the preview of this question.
diff --git a/question/bank/previewquestion/tests/behat/preview_question.feature b/question/bank/previewquestion/tests/behat/preview_question.feature
index 883886ef92c..54bbad8da42 100644
--- a/question/bank/previewquestion/tests/behat/preview_question.feature
+++ b/question/bank/previewquestion/tests/behat/preview_question.feature
@@ -18,8 +18,8 @@ Feature: A teacher can preview questions in the question bank
| user | course | role |
| teacher1 | C1 | editingteacher |
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 |
| Test questions | numerical | Test question to be previewed |
diff --git a/question/bank/previewquestion/tests/behat/preview_question_action.feature b/question/bank/previewquestion/tests/behat/preview_question_action.feature
index 8123cb5e943..02cc81fd6be 100644
--- a/question/bank/previewquestion/tests/behat/preview_question_action.feature
+++ b/question/bank/previewquestion/tests/behat/preview_question_action.feature
@@ -10,8 +10,8 @@ Feature: Use the qbank plugin manager page for previewquestion
| 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 |
diff --git a/question/bank/previewquestion/tests/qbank_preview_helper_test.php b/question/bank/previewquestion/tests/qbank_preview_helper_test.php
index 93d37082264..f171bf47c5a 100644
--- a/question/bank/previewquestion/tests/qbank_preview_helper_test.php
+++ b/question/bank/previewquestion/tests/qbank_preview_helper_test.php
@@ -75,7 +75,7 @@ class qbank_preview_helper_test extends \advanced_testcase {
$course = $generator->create_course();
$qbank = $generator->create_module('qbank', ['course' => $course->id]);
$qbankcontext = \context_module::instance($qbank->cmid);
- $this->context = context_course::instance($course->id);
+ $this->context = $qbankcontext;
// Create a question in the default category.
$contexts = new \core_question\local\bank\question_edit_contexts($qbankcontext);
$cat = question_get_default_category($contexts->lowest()->id, true);
@@ -101,7 +101,7 @@ class qbank_preview_helper_test extends \advanced_testcase {
'id' => $this->questiondata->id,
'previewid' => $this->quba->get_id(),
'returnurl' => $this->returnurl,
- 'courseid' => $this->context->instanceid,
+ 'cmid' => $this->context->instanceid,
'restartversion' => question_preview_options::ALWAYS_LATEST,
];
$params = array_merge($params, $this->options->get_url_params());
@@ -121,7 +121,7 @@ class qbank_preview_helper_test extends \advanced_testcase {
'id' => $this->questiondata->id,
'previewid' => $this->quba->get_id(),
'returnurl' => $this->returnurl,
- 'courseid' => $this->context->instanceid
+ 'cmid' => $this->context->instanceid,
];
$params = array_merge($params, $this->options->get_url_params());
$expectedurl = new moodle_url('/question/bank/previewquestion/preview.php', $params);
@@ -140,7 +140,7 @@ class qbank_preview_helper_test extends \advanced_testcase {
'id' => $this->questiondata->id,
'previewid' => $this->quba->get_id(),
'returnurl' => $this->returnurl,
- 'courseid' => $this->context->instanceid
+ 'cmid' => $this->context->instanceid,
];
$expectedurl = new moodle_url('/question/bank/previewquestion/preview.php', $params);
$this->assertEquals($expectedurl, $formurl);
@@ -158,7 +158,7 @@ class qbank_preview_helper_test extends \advanced_testcase {
'id' => $this->questiondata->id,
'behaviour' => $this->options->behaviour,
'maxmark' => $this->options->maxmark,
- 'courseid' => $this->context->instanceid,
+ 'cmid' => $this->context->instanceid,
'restartversion' => question_preview_options::ALWAYS_LATEST,
];
// Extra params for options.
@@ -186,7 +186,7 @@ class qbank_preview_helper_test extends \advanced_testcase {
'id' => $this->questiondata->id,
'behaviour' => $this->options->behaviour,
'maxmark' => $this->options->maxmark,
- 'courseid' => $this->context->instanceid,
+ 'cmid' => $this->context->instanceid,
];
// Extra params for options.
$params['correctness'] = $this->options->correctness;
diff --git a/question/bank/statistics/tests/behat/statistics_action.feature b/question/bank/statistics/tests/behat/statistics_action.feature
index 9a5b274640d..59a2e0f4c30 100644
--- a/question/bank/statistics/tests/behat/statistics_action.feature
+++ b/question/bank/statistics/tests/behat/statistics_action.feature
@@ -10,8 +10,8 @@ Feature: Use the qbank plugin manager page for statistics
| 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 |
diff --git a/question/bank/statistics/tests/behat/statistics_values.feature b/question/bank/statistics/tests/behat/statistics_values.feature
index 4b2b030b93a..bce78b1a2ed 100644
--- a/question/bank/statistics/tests/behat/statistics_values.feature
+++ b/question/bank/statistics/tests/behat/statistics_values.feature
@@ -16,19 +16,20 @@ Feature: Show statistics in question bank
| user | course | role |
| student1 | C1 | student |
| student2 | C1 | student |
+ And the following "activities" exist:
+ | activity | name | intro | course | idnumber |
+ | quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 |
+ | quiz | Quiz 2 | Quiz 2 description | C1 | quiz2 |
+ | 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 |
| 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 |
- | quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 |
- | quiz | Quiz 2 | Quiz 2 description | C1 | quiz2 |
And quiz "Quiz 1" contains the following questions:
| question | page | maxmark |
| TF1 | 1 | 1.0 |
@@ -74,7 +75,7 @@ Feature: Show statistics in question bank
| 1 | True |
| 2 | True |
And I run pending statistics recalculation tasks
- When I am on the "Course 1" "core_question > course question bank" page logged in as "admin"
+ When I am on the "Qbank 1" "core_question > question bank" page logged in as "admin"
Then I should see "50.00%" in the "TF1" "table_row"
And I should see "75.00%" in the "TF2" "table_row"
And I should see "75.00%" in the "TF3" "table_row"
@@ -90,7 +91,7 @@ Feature: Show statistics in question bank
| 1 | True |
| 2 | True |
And I run pending statistics recalculation tasks
- When I am on the "Course 1" "core_question > course question bank" page logged in as "admin"
+ When I am on the "Qbank 1" "core_question > question bank" page logged in as "admin"
Then I should see "50.00%" in the "TF1" "table_row"
And I should see "75.00%" in the "TF2" "table_row"
And I should see "75.00%" in the "TF3" "table_row"
@@ -106,7 +107,7 @@ Feature: Show statistics in question bank
| 1 | True |
| 2 | True |
And I run pending statistics recalculation tasks
- When I am on the "Course 1" "core_question > course question bank" page logged in as "admin"
+ When I am on the "Qbank 1" "core_question > question bank" page logged in as "admin"
Then I should see "Likely" in the "TF1" "table_row"
And I should see "Unlikely" in the "TF2" "table_row"
And I should see "Unlikely" in the "TF3" "table_row"
@@ -128,7 +129,7 @@ Feature: Show statistics in question bank
| 1 | True |
| 2 | False |
And I run pending statistics recalculation tasks
- When I am on the "Course 1" "core_question > course question bank" page logged in as "admin"
+ When I am on the "Qbank 1" "core_question > question bank" page logged in as "admin"
Then I should see "Likely" in the "TF1" "table_row"
And I should see "Very likely" in the "TF2" "table_row"
And I should see "Very likely" in the "TF3" "table_row"
@@ -152,7 +153,7 @@ Feature: Show statistics in question bank
| quiz | Quiz 3 | C2 | quiz3 |
And the following "question categories" exist:
| contextlevel | reference | name |
- | Course | C2 | Quiz questions |
+ | Activity module | quiz3 | Quiz questions |
And the following "questions" exist:
| questioncategory | qtype | template | name |
| Quiz questions | multichoice | one_of_four | MCA |
diff --git a/question/bank/tagquestion/classes/external/submit_tags.php b/question/bank/tagquestion/classes/external/submit_tags.php
index 0d69ad5af71..c6d43487143 100644
--- a/question/bank/tagquestion/classes/external/submit_tags.php
+++ b/question/bank/tagquestion/classes/external/submit_tags.php
@@ -99,25 +99,12 @@ class submit_tags extends external_api {
$mform = new tags_form(null, $formoptions, 'post', '', null, $cantag, $data);
if ($validateddata = $mform->get_data()) {
- if ($cantag) {
- if (isset($validateddata->tags)) {
- // Due to a mform bug, if there's no tags set on the tag element, it submits the name as the value.
- // The only way to discover is checking if the tag element is an array.
- $tags = is_array($validateddata->tags) ? $validateddata->tags : [];
-
- core_tag_tag::set_item_tags('core_question', 'question', $validateddata->id,
- $questioncontext, $tags);
-
- $result['status'] = true;
- }
-
- if (isset($validateddata->coursetags)) {
- $coursetags = is_array($validateddata->coursetags) ? $validateddata->coursetags : [];
- core_tag_tag::set_item_tags('core_question', 'question', $validateddata->id,
- $editingcontext->get_course_context(false), $coursetags);
-
- $result['status'] = true;
- }
+ if ($cantag && isset($validateddata->tags)) {
+ // Due to a mform bug, if there's no tags set on the tag element, it submits the name as the value.
+ // The only way to discover is checking if the tag element is an array.
+ $tags = is_array($validateddata->tags) ? $validateddata->tags : [];
+ core_tag_tag::set_item_tags('core_question', 'question', $validateddata->id, $questioncontext, $tags);
+ $result['status'] = true;
}
}
diff --git a/question/bank/tagquestion/classes/form/tags_form.php b/question/bank/tagquestion/classes/form/tags_form.php
index 7269b51935d..4aaa067e27f 100644
--- a/question/bank/tagquestion/classes/form/tags_form.php
+++ b/question/bank/tagquestion/classes/form/tags_form.php
@@ -63,25 +63,6 @@ class tags_form extends \moodleform {
'noselectionstring' => get_string('anytags', 'quiz'),
];
$mform->addElement('autocomplete', 'tags', get_string('tags'), $tagstrings, $options);
-
- // Is the question category in a course context?
- $qcontext = $customdata['questioncontext'];
- $qcoursecontext = $qcontext->get_course_context(false);
- $iscourseoractivityquestion = !empty($qcoursecontext);
- // Is the current context we're editing in a course context?
- $editingcontext = $customdata['editingcontext'];
- $editingcoursecontext = $editingcontext->get_course_context(false);
- $iseditingcontextcourseoractivity = !empty($editingcoursecontext);
-
- if ($iseditingcontextcourseoractivity && !$iscourseoractivityquestion) {
- // If the question is being edited in a course or activity context
- // and the question isn't a course or activity level question then
- // allow course tags to be added to the course.
- $coursetagheader = get_string('questionformtagheader', 'core_question',
- $editingcoursecontext->get_context_name(true));
- $mform->addElement('autocomplete', 'coursetags', $coursetagheader, $tagstrings, $options);
-
- }
}
}
diff --git a/question/bank/tagquestion/lib.php b/question/bank/tagquestion/lib.php
index c8390147543..bf8bfb8c70e 100644
--- a/question/bank/tagquestion/lib.php
+++ b/question/bank/tagquestion/lib.php
@@ -46,13 +46,6 @@ function qbank_tagquestion_output_fragment_tags_form($args) {
// Load the question and some related information.
$question = $DB->get_record('question', ['id' => $id]);
- if ($coursecontext = $editingcontext->get_course_context(false)) {
- $course = $DB->get_record('course', ['id' => $coursecontext->instanceid]);
- $filtercourses = [$course];
- } else {
- $filtercourses = null;
- }
-
$sql = "SELECT qc.*
FROM {question} q
JOIN {question_versions} qv ON qv.questionid = q.id
@@ -68,8 +61,7 @@ function qbank_tagquestion_output_fragment_tags_form($args) {
$tagobjectsbyquestion = core_tag_tag::get_items_tags('core_question', 'question', [$question->id]);
if (!empty($tagobjectsbyquestion[$question->id])) {
$tagobjects = $tagobjectsbyquestion[$question->id];
- $sortedtagobjects = question_sort_tags($tagobjects,
- context::instance_by_id($category->contextid), $filtercourses);
+ $sortedtagobjects = question_sort_tags($tagobjects, context::instance_by_id($category->contextid));
}
}
$formoptions = [
diff --git a/question/bank/tagquestion/tests/behat/tag_question_action.feature b/question/bank/tagquestion/tests/behat/tag_question_action.feature
index f62bf00a65d..9ab3ea1da08 100644
--- a/question/bank/tagquestion/tests/behat/tag_question_action.feature
+++ b/question/bank/tagquestion/tests/behat/tag_question_action.feature
@@ -10,8 +10,8 @@ Feature: Use the qbank plugin manager page for tagquestion
| 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 |
diff --git a/question/bank/tagquestion/tests/external/submit_tags_test.php b/question/bank/tagquestion/tests/external/submit_tags_test.php
index 4113a06bc91..126e0050931 100644
--- a/question/bank/tagquestion/tests/external/submit_tags_test.php
+++ b/question/bank/tagquestion/tests/external/submit_tags_test.php
@@ -196,182 +196,6 @@ class submit_tags_test extends \externallib_advanced_testcase {
$this->assertFalse($result['status']);
}
- /**
- * Data provided for the submit_tags_form test to check that course tags are
- * only created in the correct editing and question context combinations.
- *
- * @return array Test cases
- */
- public function get_submit_tags_form_testcases() {
- return [
- 'course - course' => [
- 'editingcontext' => 'course',
- 'questioncontext' => 'course',
- 'questiontags' => ['foo'],
- 'coursetags' => ['bar'],
- 'expectcoursetags' => false
- ],
- 'course - course - empty tags' => [
- 'editingcontext' => 'course',
- 'questioncontext' => 'course',
- 'questiontags' => [],
- 'coursetags' => ['bar'],
- 'expectcoursetags' => false
- ],
- 'course - course category' => [
- 'editingcontext' => 'course',
- 'questioncontext' => 'category',
- 'questiontags' => ['foo'],
- 'coursetags' => ['bar'],
- 'expectcoursetags' => true
- ],
- 'course - system' => [
- 'editingcontext' => 'course',
- 'questioncontext' => 'system',
- 'questiontags' => ['foo'],
- 'coursetags' => ['bar'],
- 'expectcoursetags' => true
- ],
- 'course category - course' => [
- 'editingcontext' => 'category',
- 'questioncontext' => 'course',
- 'questiontags' => ['foo'],
- 'coursetags' => ['bar'],
- 'expectcoursetags' => false
- ],
- 'course category - course category' => [
- 'editingcontext' => 'category',
- 'questioncontext' => 'category',
- 'questiontags' => ['foo'],
- 'coursetags' => ['bar'],
- 'expectcoursetags' => false
- ],
- 'course category - system' => [
- 'editingcontext' => 'category',
- 'questioncontext' => 'system',
- 'questiontags' => ['foo'],
- 'coursetags' => ['bar'],
- 'expectcoursetags' => false
- ],
- 'system - course' => [
- 'editingcontext' => 'system',
- 'questioncontext' => 'course',
- 'questiontags' => ['foo'],
- 'coursetags' => ['bar'],
- 'expectcoursetags' => false
- ],
- 'system - course category' => [
- 'editingcontext' => 'system',
- 'questioncontext' => 'category',
- 'questiontags' => ['foo'],
- 'coursetags' => ['bar'],
- 'expectcoursetags' => false
- ],
- 'system - system' => [
- 'editingcontext' => 'system',
- 'questioncontext' => 'system',
- 'questiontags' => ['foo'],
- 'coursetags' => ['bar'],
- 'expectcoursetags' => false
- ],
- ];
- }
-
- /**
- * Tests that submit_tags_form only creates course tags when the correct combination
- * of editing context and question context is provided.
- *
- * Course tags can only be set on a course category or system context question that
- * is being editing in a course context.
- *
- * @dataProvider get_submit_tags_form_testcases()
- * @param string $editingcontext The type of the context the question is being edited in
- * @param string $questioncontext The type of the context the question belongs to
- * @param string[] $questiontags The tag names to set as question tags
- * @param string[] $coursetags The tag names to set as course tags
- * @param bool $expectcoursetags If the given course tags should have been set or not
- */
- public function test_submit_tags_form_context_combinations(
- $editingcontext,
- $questioncontext,
- $questiontags,
- $coursetags,
- $expectcoursetags
- ): void {
- $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
- list ($category, $course, $qcat, $questions) = $questiongenerator->setup_course_and_questions($questioncontext);
- $coursecontext = \context_course::instance($course->id);
- $questioncontext = \context::instance_by_id($qcat->contextid);
-
- switch($editingcontext) {
- case 'system':
- $editingcontext = \context_system::instance();
- break;
-
- case 'category':
- $editingcontext = \context_coursecat::instance($category->id);
- break;
-
- default:
- $editingcontext = \context_course::instance($course->id);
- }
-
- $user = $this->create_user_can_tag($course);
- $question = $questions[0];
- $formdata = $this->generate_encoded_submit_tags_form_string(
- $question,
- $qcat,
- $questioncontext,
- $questiontags, // Question tags.
- $coursetags // Course tags.
- );
-
- $this->setUser($user);
-
- $result = submit_tags::execute($question->id, $editingcontext->id, $formdata);
-
- $this->assertTrue($result['status']);
-
- $tagobjects = \core_tag_tag::get_item_tags('core_question', 'question', $question->id);
- $coursetagobjects = [];
- $questiontagobjects = [];
-
- if ($expectcoursetags) {
- // If the use case is expecting course tags to be created then split
- // the tags into course tags and question tags and ensure we have
- // the correct number of course tags.
-
- while ($tagobject = array_shift($tagobjects)) {
- if ($tagobject->taginstancecontextid == $questioncontext->id) {
- $questiontagobjects[] = $tagobject;
- } else if ($tagobject->taginstancecontextid == $coursecontext->id) {
- $coursetagobjects[] = $tagobject;
- }
- }
-
- $this->assertCount(count($coursetags), $coursetagobjects);
- } else {
- $questiontagobjects = $tagobjects;
- }
-
- // Ensure the expected number of question tags was created.
- $this->assertCount(count($questiontags), $questiontagobjects);
-
- foreach ($questiontagobjects as $tagobject) {
- // If we have any question tags then make sure they are in the list
- // of expected tags and have the correct context.
- $this->assertContains($tagobject->name, $questiontags);
- $this->assertEquals($questioncontext->id, $tagobject->taginstancecontextid);
- }
-
- foreach ($coursetagobjects as $tagobject) {
- // If we have any course tags then make sure they are in the list
- // of expected course tags and have the correct context.
- $this->assertContains($tagobject->name, $coursetags);
- $this->assertEquals($coursecontext->id, $tagobject->taginstancecontextid);
- }
- }
-
/**
* Build the encoded form data expected by the submit_tags_form external function.
*
diff --git a/question/bank/usage/tests/behat/question_last_used_column.feature b/question/bank/usage/tests/behat/question_last_used_column.feature
index a6e13db01e2..45c6706bfec 100644
--- a/question/bank/usage/tests/behat/question_last_used_column.feature
+++ b/question/bank/usage/tests/behat/question_last_used_column.feature
@@ -10,8 +10,8 @@ Feature: Use the qbank plugin manager page for question last used
| 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 |
diff --git a/question/bank/usage/tests/behat/question_usage_column.feature b/question/bank/usage/tests/behat/question_usage_column.feature
index 39cc9dd6174..2310e78d239 100644
--- a/question/bank/usage/tests/behat/question_usage_column.feature
+++ b/question/bank/usage/tests/behat/question_usage_column.feature
@@ -10,11 +10,12 @@ Feature: Use the qbank plugin manager page for question usage
| 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 |
+ And I change window size to "large"
Scenario: Enable/disable question usage column from the base view
Given I log in as "admin"
diff --git a/question/bank/viewcreator/tests/behat/view_view_creator_column.feature b/question/bank/viewcreator/tests/behat/view_view_creator_column.feature
index 7d1cd3f293b..3fe1373dc14 100644
--- a/question/bank/viewcreator/tests/behat/view_view_creator_column.feature
+++ b/question/bank/viewcreator/tests/behat/view_view_creator_column.feature
@@ -10,8 +10,8 @@ Feature: Use the qbank plugin manager page for viewcreator plugin
| 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 |
diff --git a/question/bank/viewquestionname/tests/behat/question_in_place_editing.feature b/question/bank/viewquestionname/tests/behat/question_in_place_editing.feature
index 0fcfd19a8af..5b0b6a9ce04 100644
--- a/question/bank/viewquestionname/tests/behat/question_in_place_editing.feature
+++ b/question/bank/viewquestionname/tests/behat/question_in_place_editing.feature
@@ -15,8 +15,8 @@ Feature: Use the qbank view page to edit question title using in place edit feat
| 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 |
diff --git a/question/bank/viewquestionname/tests/behat/view_question_name_column.feature b/question/bank/viewquestionname/tests/behat/view_question_name_column.feature
index a51cb3ada94..0a6e7cc6f2f 100644
--- a/question/bank/viewquestionname/tests/behat/view_question_name_column.feature
+++ b/question/bank/viewquestionname/tests/behat/view_question_name_column.feature
@@ -10,8 +10,8 @@ Feature: Use the qbank plugin manager page for viewquestionname
| 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 |
diff --git a/question/bank/viewquestiontext/tests/behat/view_question_text_column.feature b/question/bank/viewquestiontext/tests/behat/view_question_text_column.feature
index fc653219921..50ed7969cf4 100644
--- a/question/bank/viewquestiontext/tests/behat/view_question_text_column.feature
+++ b/question/bank/viewquestiontext/tests/behat/view_question_text_column.feature
@@ -10,8 +10,8 @@ Feature: Use the qbank plugin manager page for viewquestiontext
| 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> |
diff --git a/question/bank/viewquestiontype/tests/behat/view_question_type_column.feature b/question/bank/viewquestiontype/tests/behat/view_question_type_column.feature
index faa5b4f9bfc..9279c3d51da 100644
--- a/question/bank/viewquestiontype/tests/behat/view_question_type_column.feature
+++ b/question/bank/viewquestiontype/tests/behat/view_question_type_column.feature
@@ -10,8 +10,8 @@ Feature: Use the qbank plugin manager page for viewquestiontype
| 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 |
diff --git a/question/classes/local/bank/view.php b/question/classes/local/bank/view.php
index 6d51e2dfb76..af283d1edd0 100644
--- a/question/classes/local/bank/view.php
+++ b/question/classes/local/bank/view.php
@@ -235,6 +235,10 @@ class view {
$this->cm = $cm;
$this->extraparams = $extraparams;
+ if ($cm === null) {
+ debugging('Passing $cm to the view constructor is now required.', DEBUG_DEVELOPER);
+ }
+
// Default filter condition.
if (!isset($params['filter']) && isset($params['cat'])) {
$params['filter'] = filter_condition_manager::get_default_filter($params['cat']);
@@ -251,12 +255,7 @@ class view {
// Create the url of the new question page to forward to.
$this->returnurl = $pageurl->out_as_local_url(false);
$this->editquestionurl = new \moodle_url('/question/bank/editquestion/question.php', ['returnurl' => $this->returnurl]);
- // MDL-71378 TODO: refactor this. Must require cm.
- if ($this->cm !== null) {
- $this->editquestionurl->param('cmid', $this->cm->id);
- } else {
- $this->editquestionurl->param('courseid', $this->course->id);
- }
+ $this->editquestionurl->param('cmid', $this->cm->id);
$this->lastchangedid = clean_param($pageurl->param('lastchanged'), PARAM_INT);
@@ -560,7 +559,7 @@ class view {
protected function parse_subsort($sort): array {
// Do the parsing.
if (strpos($sort, '-') !== false) {
- list($colname, $subsort) = explode('-', $sort, 2);
+ [$colname, $subsort] = explode('-', $sort, 2);
} else {
$colname = $sort;
$subsort = '';
@@ -957,7 +956,7 @@ class view {
DEBUG_DEVELOPER
);
global $DB, $OUTPUT;
- list($categoryid, $contextid) = explode(',', $categoryandcontext);
+ [$categoryid, $contextid] = explode(',', $categoryandcontext);
if (!$categoryid) {
$this->print_choose_category_message();
return false;
diff --git a/question/classes/output/question_bank_filter_ui.php b/question/classes/output/question_bank_filter_ui.php
index 20e511c548c..7535feec8df 100644
--- a/question/classes/output/question_bank_filter_ui.php
+++ b/question/classes/output/question_bank_filter_ui.php
@@ -114,14 +114,14 @@ class question_bank_filter_ui extends datafilter {
* @return stdClass Data in a format compatible with a mustache template.
*/
public function export_for_template(renderer_base $output): stdClass {
- $defaultcategory = question_get_default_category($this->context->id);
- $courseid = null;
- if ($this->context->contextlevel == CONTEXT_COURSE) {
- $courseid = $this->context->instanceid;
- }
- if (empty($courseid)) {
- $courseid = $this->searchconditions['category']->get_course_id();
+ $defaultcategory = question_get_default_category($this->context->id, true);
+
+ if ($this->context->contextlevel != CONTEXT_MODULE) {
+ debugging("Context level: {$this->context->contextlevel} is now deprecated, please use CONTEXT_MODULE");
}
+
+ $courseid = $this->context->get_course_context()->instanceid;
+
return (object) [
'tableregionid' => $this->tableregionid,
'courseid' => $courseid,
diff --git a/question/edit.php b/question/edit.php
index eb05c2479a3..f896fd67931 100644
--- a/question/edit.php
+++ b/question/edit.php
@@ -30,6 +30,11 @@ use core_question\local\bank\view;
require_once(__DIR__ . '/../config.php');
require_once($CFG->dirroot . '/question/editlib.php');
+// 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('questions', '/question/edit.php');
diff --git a/question/editlib.php b/question/editlib.php
index 60cc2f9c4c3..a50f83ab048 100644
--- a/question/editlib.php
+++ b/question/editlib.php
@@ -117,29 +117,20 @@ function get_questions_category(object $category, bool $noparent, bool $recurse
* Common setup for all pages for editing questions.
* @param string $baseurl the name of the script calling this funciton. For examle 'qusetion/edit.php'.
* @param string $edittab code for this edit tab
- * @param bool $requirecmid require cmid? default false
+ * @param bool $requirecmid This parameter has been deprecated since 4.5 and should not be used anymore.
* @param bool $unused no longer used, do no pass
* @return array $thispageurl, $contexts, $cmid, $cm, $module, $pagevars
*/
-function question_edit_setup($edittab, $baseurl, $requirecmid = false, $unused = null) {
+function question_edit_setup($edittab, $baseurl, $requirecmid = null, $unused = null) {
global $PAGE;
- if ($unused !== null) {
+ if ($unused !== null || $requirecmid !== null) {
debugging('Deprecated argument passed to question_edit_setup()', DEBUG_DEVELOPER);
}
$params = [];
- if ($requirecmid) {
- $params['cmid'] = required_param('cmid', PARAM_INT);
- } else {
- $params['cmid'] = optional_param('cmid', null, PARAM_INT);
- }
-
- if (!$params['cmid']) {
- $params['courseid'] = required_param('courseid', PARAM_INT);
- }
-
+ $params['cmid'] = required_param('cmid', PARAM_INT);
$params['qpage'] = optional_param('qpage', null, PARAM_INT);
// Pass 'cat' from page to page and when 'category' comes from a drop down menu
@@ -167,14 +158,12 @@ function question_edit_setup($edittab, $baseurl, $requirecmid = false, $unused =
* Common function for building the generic resources required by the
* editing questions pages.
*
- * Either a cmid or a course id must be provided as keys in $params or
- * an exception will be thrown. All other params are optional and will have
- * sane default applied if not provided.
+ * A cmid must be provided as a key in $params or an exception will be thrown.
+ * All other params are optional and will have sane default applied if not provided.
*
* The acceptable keys for $params are:
* [
* 'cmid' => PARAM_INT,
- * 'courseid' => PARAM_INT,
* 'qpage' => PARAM_INT,
* 'cat' => PARAM_SEQUENCE,
* 'category' => PARAM_SEQUENCE,
@@ -209,7 +198,6 @@ function question_build_edit_resources($edittab, $baseurl, $params,
];
$paramtypes = [
'cmid' => PARAM_INT,
- 'courseid' => PARAM_INT,
'qpage' => PARAM_INT,
'cat' => PARAM_SEQUENCE,
'category' => PARAM_SEQUENCE,
@@ -237,28 +225,20 @@ function question_build_edit_resources($edittab, $baseurl, $params,
}
$cmid = $cleanparams['cmid'];
- $courseid = $cleanparams['courseid'];
$qpage = $cleanparams['qpage'] ?: -1;
$cat = $cleanparams['cat'] ?: 0;
$category = $cleanparams['category'] ?: 0;
$qperpage = $cleanparams['qperpage'];
$cpage = $cleanparams['cpage'] ?: 1;
- if (is_null($cmid) && is_null($courseid)) {
- throw new \moodle_exception('Must provide a cmid or courseid');
+ if (is_null($cmid)) {
+ throw new \moodle_exception('Must provide a cmid');
}
- if ($cmid) {
- list($module, $cm) = get_module_from_cmid($cmid);
- $courseid = $cm->course;
- $thispageurl->params(compact('cmid'));
- $thiscontext = context_module::instance($cmid);
- } else {
- $module = null;
- $cm = null;
- $thispageurl->params(compact('courseid'));
- $thiscontext = context_course::instance($courseid);
- }
+ list($module, $cm) = get_module_from_cmid($cmid);
+ $courseid = $cm->course;
+ $thispageurl->params(compact('cmid'));
+ $thiscontext = context_module::instance($cmid);
if (defined('AJAX_SCRIPT') && AJAX_SCRIPT) {
// For AJAX, we don't need to set up the course page for output.
diff --git a/question/format.php b/question/format.php
index a24d9e9d9d7..68a8f46ad05 100644
--- a/question/format.php
+++ b/question/format.php
@@ -141,8 +141,12 @@ class qformat_default {
if (count($this->questions)) {
debugging('You shouldn\'t call setCategory after setQuestions');
}
+ $context = context::instance_by_id($category->contextid);
+ if ($context->contextlevel !== CONTEXT_MODULE) {
+ throw new \core\exception\moodle_exception('Invalid contextlevel for target category, must be CONTEXT_MODULE');
+ }
$this->category = $category;
- $this->importcontext = context::instance_by_id($this->category->contextid);
+ $this->importcontext = $context;
}
/**
@@ -508,30 +512,14 @@ class qformat_default {
$event->trigger();
if (core_tag_tag::is_enabled('core_question', 'question')) {
- // Is the current context we're importing in a course context?
- $importingcontext = $this->importcontext;
- $importingcoursecontext = $importingcontext->get_course_context(false);
- $isimportingcontextcourseoractivity = !empty($importingcoursecontext);
-
- if (!empty($question->coursetags)) {
- if ($isimportingcontextcourseoractivity) {
- $mergedtags = array_merge($question->coursetags, $question->tags);
-
- core_tag_tag::set_item_tags('core_question', 'question', $question->id,
- $question->context, $mergedtags);
- } else {
- core_tag_tag::set_item_tags('core_question', 'question', $question->id,
- context_course::instance($this->course->id), $question->coursetags);
-
- if (!empty($question->tags)) {
- core_tag_tag::set_item_tags('core_question', 'question', $question->id,
- $importingcontext, $question->tags);
- }
- }
- } else if (!empty($question->tags)) {
- core_tag_tag::set_item_tags('core_question', 'question', $question->id,
- $question->context, $question->tags);
- }
+ // Course tags on question now deprecated so merge them into the question tags.
+ $mergedtags = array_merge($question->coursetags ?? [], $question->tags ?? []);
+ core_tag_tag::set_item_tags('core_question',
+ 'question',
+ $question->id,
+ $question->context,
+ $mergedtags
+ );
}
if (!empty($result->error)) {
@@ -613,6 +601,14 @@ class qformat_default {
} else {
$context = context::instance_by_id($this->category->contextid);
}
+
+ // If the file had categories in a deprecated context then the categories need to be applied to a default system type
+ // mod_qbank instance on the course instead.
+ if ($context->contextlevel !== CONTEXT_MODULE) {
+ $qbank = \core_question\local\bank\question_bank_helper::get_default_open_instance_system_type($this->course, true);
+ $context = context_module::instance($qbank->id);
+ }
+
$this->importcontext = $context;
// Now create any categories that need to be created.
@@ -1026,12 +1022,10 @@ class qformat_default {
}
}
- // continue path for following error checks
- $course = $this->course;
- $continuepath = "{$CFG->wwwroot}/question/bank/exportquestions/export.php?courseid={$course->id}";
-
- // did we actually process anything
+ // Did we actually process anything? Then continue path for following error checks.
if ($count==0) {
+ $context = context::instance_by_id($contextid);
+ $continuepath = "{$CFG->wwwroot}/question/bank/exportquestions/export.php?cmid={$context->instanceid}";
throw new \moodle_exception('noquestions', 'question', $continuepath);
}
diff --git a/question/format/aiken/tests/behat/aiken_export.feature b/question/format/aiken/tests/behat/aiken_export.feature
index 7c3380ee986..de78f70f9c6 100644
--- a/question/format/aiken/tests/behat/aiken_export.feature
+++ b/question/format/aiken/tests/behat/aiken_export.feature
@@ -14,16 +14,19 @@ Feature: Test exporting questions using Aiken format.
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 the following "questions" exist:
| questioncategory | qtype | name | template |
| Test questions | multichoice | Multi-choice-001 | two_of_four |
| Test questions | multichoice | Multi-choice-002 | one_of_four |
Scenario: Aiken export
- When I am on the "Course 1" "core_question > course question export" page logged in as "teacher1"
+ When I am on the "Qbank 1" "core_question > question export" page logged in as "teacher1"
And I set the field "id_format_aiken" to "1"
When I press "Export questions to file"
Then following "click here" should download a file that:
diff --git a/question/format/aiken/tests/behat/aiken_import.feature b/question/format/aiken/tests/behat/aiken_import.feature
index 9b3ef2e0a3d..87b23c1b0f4 100644
--- a/question/format/aiken/tests/behat/aiken_import.feature
+++ b/question/format/aiken/tests/behat/aiken_import.feature
@@ -14,10 +14,13 @@ Feature: Test importing questions from Aiken format.
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 |
@javascript @_file_upload
Scenario: import some Aiken questions
- Given I am on the "Course 1" "core_question > course question import" page logged in as "teacher"
+ Given I am on the "Qbank 1" "core_question > question import" page logged in as "teacher"
And I set the field "id_format_aiken" to "1"
And I upload "question/format/aiken/tests/fixtures/questions.aiken.txt" file to "Import" filemanager
When I press "id_submitbutton"
diff --git a/question/format/aiken/tests/qformat_aiken_export_test.php b/question/format/aiken/tests/qformat_aiken_export_test.php
index 785d2c0a5a6..fe761e12485 100644
--- a/question/format/aiken/tests/qformat_aiken_export_test.php
+++ b/question/format/aiken/tests/qformat_aiken_export_test.php
@@ -59,8 +59,9 @@ class qformat_aiken_export_test extends advanced_testcase {
// Create a new course category and and a new course in that.
$category = $this->getDataGenerator()->create_category();
$course = $this->getDataGenerator()->create_course(array('category' => $category->id));
+ $qbank = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
+ $context = context_module::instance($qbank->cmid);
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
- $context = context_coursecat::instance($category->id);
$cat = $generator->create_question_category(array('contextid' => $context->id));
$question1 = $generator->create_question('shortanswer', null,
array('category' => $cat->id));
@@ -94,7 +95,8 @@ EOT;
$category = $this->getDataGenerator()->create_category();
$course = $this->getDataGenerator()->create_course(array('category' => $category->id));
$generator = $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);
$cat = $generator->create_question_category(array('contextid' => $context->id));
$question = $generator->create_question('multichoice', 'one_of_four',
array('category' => $cat->id));
diff --git a/question/format/gift/format.php b/question/format/gift/format.php
index 364ca19a3d1..016e38d7d21 100644
--- a/question/format/gift/format.php
+++ b/question/format/gift/format.php
@@ -864,7 +864,7 @@ class qformat_gift extends qformat_default {
if (!empty($tagobjects)) {
$context = context::instance_by_id($questiondata->contextid);
- $sortedtagobjects = question_sort_tags($tagobjects, $context, [$this->course]);
+ $sortedtagobjects = question_sort_tags($tagobjects, $context);
// Currently we ignore course tags. This should probably be fixed in future.
diff --git a/question/format/gift/tests/behat/import_export.feature b/question/format/gift/tests/behat/import_export.feature
index c39a92ce65a..bf5aae833df 100644
--- a/question/format/gift/tests/behat/import_export.feature
+++ b/question/format/gift/tests/behat/import_export.feature
@@ -14,7 +14,10 @@ Feature: Test importing questions from GIFT format.
And the following "course enrolments" exist:
| user | course | role |
| teacher | C1 | editingteacher |
- And I am on the "Course 1" "core_question > course question import" page logged in as "teacher"
+ And the following "activities" exist:
+ | activity | name | course | idnumber |
+ | qbank | Qbank 1 | C1 | qbank1 |
+ And I am on the "Qbank 1" "core_question > question import" page logged in as "teacher"
@javascript @_file_upload
Scenario: import some GIFT questions
@@ -28,7 +31,7 @@ Feature: Test importing questions from GIFT format.
Then I should see "colours"
# Now export again.
- And I am on the "Course 1" "core_question > course question export" page
+ And I am on the "Qbank 1" "core_question > question export" page
And I set the field "id_format_gift" to "1"
And I press "Export questions to file"
And following "click here" should download a file that:
diff --git a/question/format/xml/format.php b/question/format/xml/format.php
index 90d2f1ffc14..fca520c2468 100644
--- a/question/format/xml/format.php
+++ b/question/format/xml/format.php
@@ -1575,7 +1575,7 @@ class qformat_xml extends qformat_default {
if (!empty($tagobjects)) {
$context = context::instance_by_id($contextid);
- $sortedtagobjects = question_sort_tags($tagobjects, $context, [$this->course]);
+ $sortedtagobjects = question_sort_tags($tagobjects, $context);
if (!empty($sortedtagobjects->coursetags)) {
// Set them on the form to be rendered as existing tags.
diff --git a/question/format/xml/tests/behat/import_export.feature b/question/format/xml/tests/behat/import_export.feature
index 9e68c3684d8..4b50184d97f 100644
--- a/question/format/xml/tests/behat/import_export.feature
+++ b/question/format/xml/tests/behat/import_export.feature
@@ -14,10 +14,13 @@ Feature: Test importing questions from Moodle XML format.
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 |
@javascript @_file_upload
Scenario: import some true/false questions from Moodle XML format
- When I am on the "Course 1" "core_question > course question import" page logged in as "teacher"
+ When I am on the "Qbank 1" "core_question > question import" page logged in as "teacher"
And I set the field "id_format_xml" to "1"
And I upload "question/format/xml/tests/fixtures/truefalse.xml" file to "Import" filemanager
And I press "id_submitbutton"
@@ -30,7 +33,7 @@ Feature: Test importing questions from Moodle XML format.
Then I should see "Moodle acronym (True)"
# Now export again.
- When I am on the "Course 1" "core_question > course question export" page logged in as "teacher"
+ When I am on the "Qbank 1" "core_question > question export" page logged in as "teacher"
And I set the field "id_format_xml" to "1"
And I set the field "Export category" to "TrueFalse"
And I press "Export questions to file"
@@ -41,7 +44,7 @@ Feature: Test importing questions from Moodle XML format.
@javascript @_file_upload
Scenario: import some multiple choice questions from Moodle XML format
- When I am on the "Course 1" "core_question > course question import" page logged in as "teacher"
+ When I am on the "Qbank 1" "core_question > question import" page logged in as "teacher"
And I set the field "id_format_xml" to "1"
And I upload "question/format/xml/tests/fixtures/multichoice.xml" file to "Import" filemanager
And I press "id_submitbutton"
@@ -53,7 +56,7 @@ Feature: Test importing questions from Moodle XML format.
@javascript @_file_upload
Scenario: import some multi-answer questions from Moodle XML format
- When I am on the "Course 1" "core_question > course question import" page logged in as "teacher"
+ When I am on the "Qbank 1" "core_question > question import" page logged in as "teacher"
And I set the field "id_format_xml" to "1"
And I upload "question/format/xml/tests/fixtures/multianswer.xml" file to "Import" filemanager
And I press "id_submitbutton"
@@ -65,7 +68,7 @@ Feature: Test importing questions from Moodle XML format.
@javascript @_file_upload
Scenario: import some questions with legacy-style images from Moodle XML format
- When I am on the "Course 1" "core_question > course question import" page logged in as "teacher"
+ When I am on the "Qbank 1" "core_question > question import" page logged in as "teacher"
And I set the field "id_format_xml" to "1"
And I upload "question/format/xml/tests/fixtures/sample_questions_with_old_image_tag.xml" file to "Import" filemanager
And I press "id_submitbutton"
diff --git a/question/format/xml/tests/fixtures/categories_reverse_order.xml b/question/format/xml/tests/fixtures/categories_reverse_order.xml
index 77e003287de..3d4dcc629fc 100644
--- a/question/format/xml/tests/fixtures/categories_reverse_order.xml
+++ b/question/format/xml/tests/fixtures/categories_reverse_order.xml
@@ -3,7 +3,7 @@
- $course$/Sigma/Tau
+ $module$/Sigma/Tau
This is Tau category for test
@@ -40,7 +40,7 @@
- $course$/Sigma
+ $module$/Sigma
This is Sigma category for test
diff --git a/question/format/xml/tests/fixtures/category_with_description.xml b/question/format/xml/tests/fixtures/category_with_description.xml
index 674457bab42..31610569772 100644
--- a/question/format/xml/tests/fixtures/category_with_description.xml
+++ b/question/format/xml/tests/fixtures/category_with_description.xml
@@ -3,7 +3,7 @@
- $course$/Alpha
+ $module$/Alpha
This is Alpha category for test
diff --git a/question/format/xml/tests/fixtures/deprecated_category.xml b/question/format/xml/tests/fixtures/deprecated_category.xml
new file mode 100644
index 00000000000..40f547d3b91
--- /dev/null
+++ b/question/format/xml/tests/fixtures/deprecated_category.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+ $course$/Alpha
+
+
+ This is Alpha category for test
+
+ alpha-idnumber
+
+
+
+
+ Alpha Question
+
+
+ Testing Alpha Question
]]>
+
+
+
+
+ 1.0000000
+ 1.0000000
+ 0
+
+ true
+
+
+
+
+
+ false
+
+
+
+
+
+
diff --git a/question/format/xml/tests/fixtures/export_category.xml b/question/format/xml/tests/fixtures/export_category.xml
index 63087cf7264..890ab7f15ef 100644
--- a/question/format/xml/tests/fixtures/export_category.xml
+++ b/question/format/xml/tests/fixtures/export_category.xml
@@ -3,7 +3,7 @@
- $course$/Alpha
+ $module$/Alpha
This is Alpha category for test
diff --git a/question/format/xml/tests/fixtures/html_chars_in_idnumbers.xml b/question/format/xml/tests/fixtures/html_chars_in_idnumbers.xml
index cc1d37676e9..323032917ad 100644
--- a/question/format/xml/tests/fixtures/html_chars_in_idnumbers.xml
+++ b/question/format/xml/tests/fixtures/html_chars_in_idnumbers.xml
@@ -3,7 +3,7 @@
- $course$/Alpha
+ $module$/Alpha
This is Alpha category for test
diff --git a/question/format/xml/tests/fixtures/multianswer.xml b/question/format/xml/tests/fixtures/multianswer.xml
index 5a3cc3422a6..a96071a190c 100644
--- a/question/format/xml/tests/fixtures/multianswer.xml
+++ b/question/format/xml/tests/fixtures/multianswer.xml
@@ -3,7 +3,7 @@
- $course$/Default for Test images in backup
+ $module$/Default for Test images in backup
diff --git a/question/format/xml/tests/fixtures/multichoice.xml b/question/format/xml/tests/fixtures/multichoice.xml
index dbf58455cf9..a023996dda2 100644
--- a/question/format/xml/tests/fixtures/multichoice.xml
+++ b/question/format/xml/tests/fixtures/multichoice.xml
@@ -3,7 +3,7 @@
- $course$/Default for testhead/Multichoice
+ $module$/Default for testhead/Multichoice
diff --git a/question/format/xml/tests/fixtures/nested_categories.xml b/question/format/xml/tests/fixtures/nested_categories.xml
index ac6db64d315..5db1145f635 100644
--- a/question/format/xml/tests/fixtures/nested_categories.xml
+++ b/question/format/xml/tests/fixtures/nested_categories.xml
@@ -3,7 +3,7 @@
- $course$/Delta
+ $module$/Delta
This is Delta category for test
@@ -14,7 +14,7 @@
- $course$/Delta/Epsilon
+ $module$/Delta/Epsilon
This is Epsilon category for test
@@ -25,7 +25,7 @@
- $course$/Delta/Epsilon/Zeta
+ $module$/Delta/Epsilon/Zeta
This is Zeta category for test
diff --git a/question/format/xml/tests/fixtures/nested_categories_with_questions.xml b/question/format/xml/tests/fixtures/nested_categories_with_questions.xml
index cca8027ec0b..9032fa715da 100644
--- a/question/format/xml/tests/fixtures/nested_categories_with_questions.xml
+++ b/question/format/xml/tests/fixtures/nested_categories_with_questions.xml
@@ -3,7 +3,7 @@
- $course$/Iota
+ $module$/Iota
This is Iota category for test
@@ -43,7 +43,7 @@
- $course$/Iota/Kappa
+ $module$/Iota/Kappa
This is Kappa category for test
@@ -115,7 +115,7 @@
- $course$/Iota/Kappa/Lambda
+ $module$/Iota/Kappa/Lambda
This is Lambda category for test
@@ -155,7 +155,7 @@
- $course$/Iota/Mu
+ $module$/Iota/Mu
This is Mu category for test
diff --git a/question/format/xml/tests/fixtures/old_format_file.xml b/question/format/xml/tests/fixtures/old_format_file.xml
index efc900702b3..3665f644524 100644
--- a/question/format/xml/tests/fixtures/old_format_file.xml
+++ b/question/format/xml/tests/fixtures/old_format_file.xml
@@ -3,7 +3,7 @@
- $course$/Pi
+ $module$/Pi
@@ -38,7 +38,7 @@
- $course$/Pi/Rho
+ $module$/Pi/Rho
diff --git a/question/format/xml/tests/fixtures/sample_questions_with_old_image_tag.xml b/question/format/xml/tests/fixtures/sample_questions_with_old_image_tag.xml
index 852e5bc1979..69cc125ecdd 100644
--- a/question/format/xml/tests/fixtures/sample_questions_with_old_image_tag.xml
+++ b/question/format/xml/tests/fixtures/sample_questions_with_old_image_tag.xml
@@ -5,7 +5,7 @@
- $course$/Default for Test images in backup
+ $module$/Default for Test images in backup
diff --git a/question/format/xml/tests/fixtures/truefalse.xml b/question/format/xml/tests/fixtures/truefalse.xml
index 97b099a42fa..bee898d1a7f 100644
--- a/question/format/xml/tests/fixtures/truefalse.xml
+++ b/question/format/xml/tests/fixtures/truefalse.xml
@@ -3,7 +3,7 @@
- $course$/Default for testhead/TrueFalse
+ $module$/Default for testhead/TrueFalse
diff --git a/question/format/xml/tests/qformat_xml_import_export_test.php b/question/format/xml/tests/qformat_xml_import_export_test.php
index 99a39c8b635..1296f9e2c77 100644
--- a/question/format/xml/tests/qformat_xml_import_export_test.php
+++ b/question/format/xml/tests/qformat_xml_import_export_test.php
@@ -21,7 +21,6 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-use core_question\local\bank\question_edit_contexts;
defined('MOODLE_INTERNAL') || die();
global $CFG;
@@ -39,15 +38,21 @@ require_once($CFG->dirroot . '/question/editlib.php');
* @covers \qformat_xml
*/
class qformat_xml_import_export_test extends advanced_testcase {
+
+ /** @var stdClass mod_qbank instance */
+ private stdClass $qbank;
+
/**
* Create object qformat_xml for test.
* @param string $filename with name for testing file.
- * @param stdClass $course
* @return qformat_xml XML question format object.
*/
- public function create_qformat($filename, $course) {
+ public function create_qformat($filename) {
+ $course = self::getDataGenerator()->create_course();
+ $qbank = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
+
$qformat = new qformat_xml();
- $qformat->setContexts((new question_edit_contexts(context_course::instance($course->id)))->all());
+ $qformat->setContexts([context_module::instance($qbank->cmid)]);
$qformat->setCourse($course);
$qformat->setFilename(__DIR__ . '/fixtures/' . $filename);
$qformat->setRealfilename($filename);
@@ -59,6 +64,8 @@ class qformat_xml_import_export_test extends advanced_testcase {
$qformat->setContexttofile(1);
$qformat->set_display_progress(false);
+ $this->qbank = $qbank;
+
return $qformat;
}
@@ -150,7 +157,7 @@ class qformat_xml_import_export_test extends advanced_testcase {
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$this->setAdminUser();
- $qformat = $this->create_qformat('category_with_description.xml', $course);
+ $qformat = $this->create_qformat('category_with_description.xml');
$imported = $qformat->importprocess();
$this->assertTrue($imported);
$this->assert_category_imported('Alpha',
@@ -168,8 +175,7 @@ class qformat_xml_import_export_test extends advanced_testcase {
$this->resetAfterTest();
self::setAdminUser();
- $course = self::getDataGenerator()->create_course();
- $qformat = $this->create_qformat('deprecated_category.xml', $course);
+ $qformat = $this->create_qformat('deprecated_category.xml');
$cat = question_get_default_category($qformat->contexts[0]->id, true);
$qformat->setCategory($cat);
$imported = $qformat->importprocess();
@@ -183,9 +189,8 @@ class qformat_xml_import_export_test extends advanced_testcase {
*/
public function test_import_nested_categories(): void {
$this->resetAfterTest();
- $course = $this->getDataGenerator()->create_course();
$this->setAdminUser();
- $qformat = $this->create_qformat('nested_categories.xml', $course);
+ $qformat = $this->create_qformat('nested_categories.xml');
$imported = $qformat->importprocess();
$this->assertTrue($imported);
$this->assert_category_imported('Delta', 'This is Delta category for test', FORMAT_PLAIN);
@@ -201,9 +206,8 @@ class qformat_xml_import_export_test extends advanced_testcase {
*/
public function test_import_nested_categories_with_questions(): void {
$this->resetAfterTest();
- $course = $this->getDataGenerator()->create_course();
$this->setAdminUser();
- $qformat = $this->create_qformat('nested_categories_with_questions.xml', $course);
+ $qformat = $this->create_qformat('nested_categories_with_questions.xml');
$imported = $qformat->importprocess();
$this->assertTrue($imported);
$this->assert_category_imported('Iota', 'This is Iota category for test', FORMAT_PLAIN);
@@ -225,9 +229,8 @@ class qformat_xml_import_export_test extends advanced_testcase {
*/
public function test_import_old_format(): void {
$this->resetAfterTest();
- $course = $this->getDataGenerator()->create_course();
$this->setAdminUser();
- $qformat = $this->create_qformat('old_format_file.xml', $course);
+ $qformat = $this->create_qformat('old_format_file.xml');
$imported = $qformat->importprocess();
$this->assertTrue($imported);
$this->assert_category_imported('Pi', '', FORMAT_MOODLE);
@@ -243,9 +246,8 @@ class qformat_xml_import_export_test extends advanced_testcase {
*/
public function test_import_categories_in_reverse_order(): void {
$this->resetAfterTest();
- $course = $this->getDataGenerator()->create_course();
$this->setAdminUser();
- $qformat = $this->create_qformat('categories_reverse_order.xml', $course);
+ $qformat = $this->create_qformat('categories_reverse_order.xml');
$imported = $qformat->importprocess();
$this->assertTrue($imported);
$this->assert_category_imported('Sigma', 'This is Sigma category for test', FORMAT_HTML);
@@ -265,9 +267,8 @@ class qformat_xml_import_export_test extends advanced_testcase {
global $OUTPUT;
$this->resetAfterTest(true);
- $course = $this->getDataGenerator()->create_course();
$this->setAdminUser();
- $qformat = $this->create_qformat('error_invalid_grades.xml', $course);
+ $qformat = $this->create_qformat('error_invalid_grades.xml');
ob_start();
$imported = $qformat->importprocess();
@@ -293,11 +294,11 @@ class qformat_xml_import_export_test extends advanced_testcase {
// Note while this loads $qformat with all the 'right' data from the xml file,
// the call to setCategory, followed by exportprocess will actually only export data
// from the database (created by the generator).
- $qformat = $this->create_qformat('export_category.xml', $SITE);
+ $qformat = $this->create_qformat('export_category.xml');
$category = $generator->create_question_category([
'name' => 'Alpha',
- 'contextid' => context_course::instance($SITE->id)->id,
+ 'contextid' => context_module::instance($this->qbank->cmid)->id,
'info' => 'This is Alpha category for test',
'infoformat' => '0',
'idnumber' => 'alpha-idnumber',
@@ -328,11 +329,11 @@ class qformat_xml_import_export_test extends advanced_testcase {
$this->resetAfterTest();
$this->setAdminUser();
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
- $qformat = $this->create_qformat('nested_categories.zml', $SITE);
+ $qformat = $this->create_qformat('nested_categories.xml');
$categorydelta = $generator->create_question_category([
'name' => 'Delta',
- 'contextid' => context_course::instance($SITE->id)->id,
+ 'contextid' => context_module::instance($this->qbank->cmid)->id,
'info' => 'This is Delta category for test',
'infoformat' => '2',
'stamp' => make_unique_id_code(),
@@ -340,7 +341,7 @@ class qformat_xml_import_export_test extends advanced_testcase {
'sortorder' => '999']);
$categoryepsilon = $generator->create_question_category([
'name' => 'Epsilon',
- 'contextid' => context_course::instance($SITE->id)->id,
+ 'contextid' => context_module::instance($this->qbank->cmid)->id,
'info' => 'This is Epsilon category for test',
'infoformat' => '4',
'stamp' => make_unique_id_code(),
@@ -348,7 +349,7 @@ class qformat_xml_import_export_test extends advanced_testcase {
'sortorder' => '999']);
$categoryzeta = $generator->create_question_category([
'name' => 'Zeta',
- 'contextid' => context_course::instance($SITE->id)->id,
+ 'contextid' => context_module::instance($this->qbank->cmid)->id,
'info' => 'This is Zeta category for test',
'infoformat' => '0',
'stamp' => make_unique_id_code(),
@@ -382,11 +383,11 @@ class qformat_xml_import_export_test extends advanced_testcase {
$this->resetAfterTest();
$this->setAdminUser();
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
- $qformat = $this->create_qformat('nested_categories_with_questions.xml', $SITE);
+ $qformat = $this->create_qformat('nested_categories_with_questions.xml');
$categoryiota = $generator->create_question_category([
'name' => 'Iota',
- 'contextid' => context_course::instance($SITE->id)->id,
+ 'contextid' => context_module::instance($this->qbank->cmid)->id,
'info' => 'This is Iota category for test',
'infoformat' => '2',
'stamp' => make_unique_id_code(),
@@ -405,7 +406,7 @@ class qformat_xml_import_export_test extends advanced_testcase {
'penalty' => '1']);
$categorykappa = $generator->create_question_category([
'name' => 'Kappa',
- 'contextid' => context_course::instance($SITE->id)->id,
+ 'contextid' => context_module::instance($this->qbank->cmid)->id,
'info' => 'This is Kappa category for test',
'infoformat' => '4',
'stamp' => make_unique_id_code(),
@@ -441,7 +442,7 @@ class qformat_xml_import_export_test extends advanced_testcase {
'idnumber' => '']);
$categorylambda = $generator->create_question_category([
'name' => 'Lambda',
- 'contextid' => context_course::instance($SITE->id)->id,
+ 'contextid' => context_module::instance($this->qbank->cmid)->id,
'info' => 'This is Lambda category for test',
'infoformat' => '0',
'stamp' => make_unique_id_code(),
@@ -460,7 +461,7 @@ class qformat_xml_import_export_test extends advanced_testcase {
'penalty' => '1']);
$categorymu = $generator->create_question_category([
'name' => 'Mu',
- 'contextid' => context_course::instance($SITE->id)->id,
+ 'contextid' => context_module::instance($this->qbank->cmid)->id,
'info' => 'This is Mu category for test',
'infoformat' => '0',
'stamp' => make_unique_id_code(),
@@ -495,11 +496,11 @@ class qformat_xml_import_export_test extends advanced_testcase {
// Note while this loads $qformat with all the 'right' data from the xml file,
// the call to setCategory, followed by exportprocess will actually only export data
// from the database (created by the generator).
- $qformat = $this->create_qformat('export_category.xml', $SITE);
+ $qformat = $this->create_qformat('export_category.xml');
$category = $generator->create_question_category([
'name' => 'Alpha',
- 'contextid' => context_course::instance($SITE->id)->id,
+ 'contextid' => context_module::instance($this->qbank->cmid)->id,
'info' => 'This is Alpha category for test',
'infoformat' => '0',
'idnumber' => 'The inequalities < & >',
diff --git a/question/templates/qbank_action_menu.mustache b/question/templates/qbank_action_menu.mustache
index dde72909e32..0d1d93bbb9f 100644
--- a/question/templates/qbank_action_menu.mustache
+++ b/question/templates/qbank_action_menu.mustache
@@ -36,22 +36,22 @@
"options": [{
"name": "Questions",
"selected": true,
- "value": "/question/edit.php?courseid=7"
+ "value": "/question/edit.php?cmid=7"
},
{
"name": "Categories",
"selected": false,
- "value": "/question/bank/managecategories/category.php?courseid=7"
+ "value": "/question/bank/managecategories/category.php?cmid=7"
},
{
"name": "Import",
"selected": false,
- "value": "/question/bank/importquestions/import.php?courseid=7"
+ "value": "/question/bank/importquestions/import.php?cmid=7"
},
{
"name": "Export",
"selected": false,
- "value": "/question/bank/exportquestions/export.php?courseid=7"
+ "value": "/question/bank/exportquestions/export.php?cmid=7"
}
]
},
diff --git a/question/tests/backup_test.php b/question/tests/backup_test.php
index f06775a308e..b166afbfe15 100644
--- a/question/tests/backup_test.php
+++ b/question/tests/backup_test.php
@@ -431,6 +431,7 @@ class backup_test extends \advanced_testcase {
// Create a course and a category.
$course = $this->getDataGenerator()->create_course();
+ $qbank = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
$category = $this->getDataGenerator()->create_category();
// Create a question with links in all the places that should be recoded.
@@ -438,7 +439,7 @@ class backup_test extends \advanced_testcase {
$testcontent = 'Look at the course.';
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$questioncategory = $questiongenerator->create_question_category(
- ['contextid' => context_course::instance($course->id)->id]);
+ ['contextid' => \context_module::instance($qbank->cmid)->id]);
$question = $questiongenerator->create_question('multichoice', null, [
'name' => 'Test question',
'category' => $questioncategory->id,
@@ -461,7 +462,11 @@ class backup_test extends \advanced_testcase {
// Backup and restore the course.
$backupid = $this->backup_course($course);
- $newcourseid = $this->restore_course($backupid, 'New course', 'C2', $category->id);
+ $newcourse = $this->getDataGenerator()->create_course();
+ $this->restore_to_course($backupid, $newcourse->id);
+ $modinfo = get_fast_modinfo($newcourse);
+ $qbanks = $modinfo->get_instances_of('qbank');
+ $qbank = reset($qbanks);
// Get the question from the restored course - we are expecting just one, but that is not the real test here.
$restoredquestions = $DB->get_records_sql("
@@ -471,14 +476,14 @@ class backup_test extends \advanced_testcase {
JOIN {question_bank_entries} qbe ON qbe.id = qv.questionbankentryid
JOIN {question_categories} qc ON qc.id = qbe.questioncategoryid
WHERE qc.contextid = ?
- ", [context_course::instance($newcourseid)->id]);
+ ", [\context_module::instance($qbank->id)->id]);
$this->assertCount(1, $restoredquestions);
$questionid = array_key_first($restoredquestions);
$this->assertEquals('Test question', $restoredquestions[$questionid]->name);
// Verify the links have been recoded.
$restoredquestion = question_bank::load_question_data($questionid);
- $recodedlink = new moodle_url('/course/view.php', ['id' => $newcourseid]);
+ $recodedlink = new moodle_url('/course/view.php', ['id' => $newcourse->id]);
$recodedcontent = 'Look at the course.';
$firstanswerid = array_key_first($restoredquestion->options->answers);
$firsthintid = array_key_first($restoredquestion->hints);
diff --git a/question/tests/behat/bank_add_default_shared.feature b/question/tests/behat/bank_add_default_shared.feature
index 24465c1549f..fb23c9407bc 100644
--- a/question/tests/behat/bank_add_default_shared.feature
+++ b/question/tests/behat/bank_add_default_shared.feature
@@ -14,7 +14,6 @@ Feature: Add a default question bank
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
- | student1 | C1 | student |
Scenario: Add a default question bank to a course
Given I am on the "C1" "Course" page logged in as "teacher1"
diff --git a/question/tests/behat/bank_view.feature b/question/tests/behat/bank_view.feature
index 37fdd59e3e2..c28ab843156 100644
--- a/question/tests/behat/bank_view.feature
+++ b/question/tests/behat/bank_view.feature
@@ -14,9 +14,12 @@ Feature: A bank view with questions can be managed
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 |
@javascript
Scenario: Viewing question bank should not load individual questions
@@ -25,7 +28,8 @@ Feature: A bank view with questions can be managed
| Test questions | essay | Essay test question | Write about whatever you want | qid |
| Test questions | numerical | Numerical test question | Write about whatever you want | qid |
And I am on the "C1" "Course" page logged in as "teacher1"
- 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 should see "Essay test question"
And I should see "Numerical test question"
And I choose "Delete" action for "Essay test question" in the question bank
@@ -42,7 +46,8 @@ Feature: A bank view with questions can be managed
| Test questions | truefalse | Truefalse type question | Write about whatever you want |
| Test questions | essay | Essay type question | Write about whatever you want |
And I am on the "C1" "Course" page logged in as "teacher1"
- 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 should see "Unknown type question"
And I should see "Truefalse type question"
And I should see "Essay type question"
diff --git a/question/tests/behat/behat_core_question.php b/question/tests/behat/behat_core_question.php
index d2476c12da7..1131437f83c 100644
--- a/question/tests/behat/behat_core_question.php
+++ b/question/tests/behat/behat_core_question.php
@@ -53,12 +53,15 @@ class behat_core_question extends behat_question_base {
* Convert page names to URLs for steps like 'When I am on the "[identifier]" "[page type]" page'.
*
* Recognised page names are:
- * | pagetype | name meaning | description |
- * | course question bank | Course name | The question bank for a course |
- * | course question import | Course name | The import questions screen for a course |
- * | course question export | Course name | The export questions screen for a course |
- * | preview | Question name | The screen to preview a question |
- * | edit | Question name | The screen to edit a question |
+ * | pagetype | name meaning | description |
+ * | course question bank | Course name | The default question bank for a course |
+ * | course question import | Course name | The import questions screen for a course default bank |
+ * | course question export | Course name | The export questions screen for a course default bank |
+ * | question bank | Question bank name | The question bank module |
+ * | question import | Question bank name | The import questions screen for a question bank |
+ * | question export | Question bank name | The export questions screen for a question bank |
+ * | preview | Question name | The screen to preview a question |
+ * | edit | Question name | The screen to edit a question |
*
* @param string $type identifies which type of page this is, e.g. 'Preview'.
* @param string $identifier identifies the particular page, e.g. 'My question'.
@@ -71,21 +74,51 @@ class behat_core_question extends behat_question_base {
// The question bank does not handle fields at the edge of the viewport well.
// Increase the size to avoid this.
$this->execute('behat_general::i_change_window_size_to', ['window', 'large']);
+ $qbank = $this->get_default_bank_for_course_identifier($identifier);
return new moodle_url('/question/edit.php', [
- 'courseid' => $this->get_course_id($identifier),
+ 'cmid' => $qbank->id,
]);
+ case 'question bank':
+ // The question bank does not handle fields at the edge of the viewport well.
+ // Increase the size to avoid this.
+ $this->execute('behat_general::i_change_window_size_to', ['window', 'large']);
+ return new moodle_url('/question/edit.php',
+ ['cmid' => $this->get_cm_by_activity_name('qbank', $identifier)->id]
+ );
+
case 'course question categories':
+ $qbank = $this->get_default_bank_for_course_identifier($identifier);
return new moodle_url('/question/bank/managecategories/category.php',
- ['courseid' => $this->get_course_id($identifier)]);
+ ['cmid' => $qbank->id]
+ );
+
+ case 'question categories':
+ return new moodle_url('/question/bank/managecategories/category.php',
+ ['cmid' => $this->get_cm_by_activity_name('qbank', $identifier)->id]
+ );
case 'course question import':
+ $qbank = $this->get_default_bank_for_course_identifier($identifier);
return new moodle_url('/question/bank/importquestions/import.php',
- ['courseid' => $this->get_course_id($identifier)]);
+ ['cmid' => $qbank->id]
+ );
+
+ case 'question import':
+ return new moodle_url('/question/bank/importquestions/import.php',
+ ['cmid' => $this->get_cm_by_activity_name('qbank', $identifier)->id]
+ );
case 'course question export':
+ $qbank = $this->get_default_bank_for_course_identifier($identifier);
return new moodle_url('/question/bank/exportquestions/export.php',
- ['courseid' => $this->get_course_id($identifier)]);
+ ['cmid' => $qbank->id]
+ );
+
+ case 'question export':
+ return new moodle_url('/question/bank/exportquestions/export.php',
+ ['cmid' => $this->get_cm_by_activity_name('qbank', $identifier)->id]
+ );
case 'preview':
[$questionid, $otheridtype, $otherid] = $this->find_question_by_name($identifier);
@@ -102,6 +135,17 @@ class behat_core_question extends behat_question_base {
}
}
+ /**
+ * Get the course default question bank, creating it if it doesn't yet exist
+ *
+ * @param string $identifier The name of the course to add a default bank to.
+ * @return cm_info The newly created default question bank.
+ */
+ private function get_default_bank_for_course_identifier(string $identifier): cm_info {
+ $course = get_course($this->get_course_id($identifier));
+ return \core_question\local\bank\question_bank_helper::get_default_open_instance_system_type($course, true);
+ }
+
/**
* Find a question, and where it is, from the question name.
*
diff --git a/question/tests/behat/delete_questions.feature b/question/tests/behat/delete_questions.feature
index 7cb1f6f8e10..26a7f921c7b 100644
--- a/question/tests/behat/delete_questions.feature
+++ b/question/tests/behat/delete_questions.feature
@@ -14,13 +14,16 @@ Feature: A teacher can delete questions in the question bank
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
+ 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 | essay | Test question to be deleted | Write about whatever you want |
- And I am on the "Course 1" "core_question > course question bank" page logged in as "teacher1"
+ And I am on the "Qbank 1" "core_question > question bank" page logged in as "teacher1"
@javascript
Scenario: A question not used anywhere can really be deleted
@@ -49,7 +52,7 @@ Feature: A teacher can delete questions in the question bank
And quiz "Test quiz" contains the following questions:
| question | page | requireprevious |
| Test used question to be deleted | 1 | 0 |
- When I am on the "Course 1" "core_question > course question bank" page
+ When I am on the "Qbank 1" "core_question > question bank" page
And I choose "Delete" action for "Test used question to be deleted" in the question bank
And I should see "This will delete the following question and all its versions:"
And I should see "* Denotes questions which can't be deleted because they are in use. Instead, they will be hidden in the question bank unless you set 'Show hidden questions' to 'Yes'."
@@ -74,7 +77,7 @@ Feature: A teacher can delete questions in the question bank
@javascript
Scenario: Delete question has multiple versions in question bank page
- Given I am on the "Course 1" "core_question > course question bank" page logged in as "teacher1"
+ Given I am on the "Qbank 1" "core_question > question bank" page logged in as "teacher1"
When the following "core_question > updated questions" exist:
| questioncategory | question | questiontext |
| Test questions | Test question to be deleted | Test question to be deleted version 2 |
diff --git a/question/tests/behat/duplicate_questions.feature b/question/tests/behat/duplicate_questions.feature
index 0b762b548fc..eacef35d1bd 100644
--- a/question/tests/behat/duplicate_questions.feature
+++ b/question/tests/behat/duplicate_questions.feature
@@ -14,13 +14,16 @@ Feature: A teacher can duplicate questions in the question bank
And the following "course enrolments" exist:
| user | course | role |
| teacher | C1 | editingteacher |
+ 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 | idnumber |
| Test questions | essay | Test question to be copied | Write about whatever you want | qid |
- And I am on the "Course 1" "core_question > course question bank" page logged in as "teacher"
+ And I am on the "Qbank 1" "core_question > question bank" page logged in as "teacher"
Scenario: Duplicating a previously created question
When I choose "Duplicate" action for "Test question to be copied" in the question bank
diff --git a/question/tests/behat/edit_question_tags.feature b/question/tests/behat/edit_question_tags.feature
index f623128010c..9d09432a8ea 100644
--- a/question/tests/behat/edit_question_tags.feature
+++ b/question/tests/behat/edit_question_tags.feature
@@ -14,13 +14,16 @@ Feature: A teacher can manage tags on questions in the question bank
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
+ 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 | essay | Test question to be tagged | Write about whatever you want |
- And I am on the "Course 1" "core_question > course question bank" page logged in as "teacher1"
+ And I am on the "Qbank 1" "core_question > question bank" page logged in as "teacher1"
@javascript
Scenario: Manage tags on a question
diff --git a/question/tests/behat/edit_question_versioning.feature b/question/tests/behat/edit_question_versioning.feature
index 4fa0bf7f561..9717cf6b1cb 100644
--- a/question/tests/behat/edit_question_versioning.feature
+++ b/question/tests/behat/edit_question_versioning.feature
@@ -14,12 +14,12 @@ Feature: Questions in the question bank have versions
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 |
+ And the following "question categories" exist:
+ | contextlevel | reference | name |
+ | Activity module | quiz1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext | answer 1 |
| Test questions | truefalse | First question | Answer the first question | True |
@@ -29,13 +29,13 @@ Feature: Questions in the question bank have versions
@javascript
Scenario: Question version is displayed
- Given I am on the "Course 1" "core_question > course question bank" page logged in as "teacher1"
+ Given I am on the "Quiz 1" "mod_quiz > question bank" page logged in as "teacher1"
When I choose "Edit question" action for "First question" in the question bank
Then I should see "Version 1"
@javascript
Scenario: Question version change when question is altered
- Given I am on the "Course 1" "core_question > course question bank" page logged in as "teacher1"
+ Given I am on the "Quiz 1" "mod_quiz > question bank" page logged in as "teacher1"
When I choose "Edit question" action for "First question" in the question bank
And I should see "Version 1"
When I set the field "id_name" to "Renamed question v2"
diff --git a/question/tests/behat/edit_questions.feature b/question/tests/behat/edit_questions.feature
index 0414ff30d34..2df7036a627 100644
--- a/question/tests/behat/edit_questions.feature
+++ b/question/tests/behat/edit_questions.feature
@@ -14,13 +14,16 @@ Feature: A teacher can edit questions in the question bank
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
+ 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 | essay | Test question to be edited | Write about whatever you want |
- And I am on the "Course 1" "core_question > course question bank" page logged in as "teacher1"
+ And I am on the "Qbank 1" "core_question > question bank" page logged in as "teacher1"
@javascript
Scenario: Edit a previously created question
@@ -72,7 +75,7 @@ Feature: A teacher can edit questions in the question bank
Given the following "questions" exist:
| questioncategory | qtype | name | idnumber |
| Test questions | essay | Question with idnumber | frog |
- When I am on the "Course 1" "core_question > course question bank" page logged in as "teacher1"
+ When I am on the "Qbank 1" "core_question > question bank" page logged in as "teacher1"
Then I should see "frog" in the "Question with idnumber" "table_row"
When I choose "Edit question" action for "Question with idnumber" in the question bank
And I set the field "ID number" to ""
@@ -83,7 +86,7 @@ Feature: A teacher can edit questions in the question bank
Given the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | missingtype | Broken question | Write something |
- When I am on the "Course 1" "core_question > course question bank" page logged in as "teacher1"
+ When I am on the "Qbank 1" "core_question > question bank" page logged in as "teacher1"
Then the "Edit question" item should not exist in the "Edit" action menu of the "Broken question" "table_row"
And the "Duplicate" item should not exist in the "Edit" action menu of the "Broken question" "table_row"
And the "Preview" item should not exist in the "Edit" action menu of the "Broken question" "table_row"
diff --git a/question/tests/behat/edit_questions_standard_tags.feature b/question/tests/behat/edit_questions_standard_tags.feature
index 0aacb5db6f0..dcfd86a4999 100644
--- a/question/tests/behat/edit_questions_standard_tags.feature
+++ b/question/tests/behat/edit_questions_standard_tags.feature
@@ -14,13 +14,16 @@ Feature: The questions can be tagged
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
+ And the following "activities" exist:
+ | activity | name | intro | course | idnumber |
+ | qbank | Qbank 1 | Question bank 1 | C1 | qbank1 |
And the following "tags" exist:
| name | isstandard |
| foo | 1 |
| bar | 1 |
Scenario: The tags autocomplete should include standard tags
- When I am on the "Course 1" "core_question > course question bank" page logged in as "teacher1"
+ When I am on the "Qbank 1" "core_question > question bank" page logged in as "teacher1"
And I press "Create a new question ..."
And I set the field "item_qtype_truefalse" to "1"
And I click on "Add" "button" in the "Choose a question type to add" "dialogue"
diff --git a/question/tests/behat/filter_questions_by_tag.feature b/question/tests/behat/filter_questions_by_tag.feature
index 4432999b305..5de2b7a7d74 100644
--- a/question/tests/behat/filter_questions_by_tag.feature
+++ b/question/tests/behat/filter_questions_by_tag.feature
@@ -14,9 +14,12 @@ Feature: The questions in the question bank can be filtered by tags
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
+ 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 | user | questiontext |
| Test questions | essay | question 1 name | admin | Question 1 text |
@@ -26,6 +29,7 @@ Feature: The questions in the question bank can be filtered by tags
| Tags | foo |
And I press "id_submitbutton"
And I am on the "question 2 name" "core_question > edit" page
+ And I change window size to "large"
And I set the following fields to these values:
| Tags | bar |
And I press "id_submitbutton"
@@ -38,7 +42,7 @@ Feature: The questions in the question bank can be filtered by tags
@javascript
Scenario: Empty condition should not result in exception
- When I am on the "Course 1" "core_question > course question bank" page
+ When I am on the "Qbank 1" "core_question > question bank" page
And I set the field "Type or select..." in the "Filter 1" "fieldset" to "Test questions"
When I click on "Add condition" "button"
And I set the field "type" in the "Filter 2" "fieldset" to "Tag"
diff --git a/question/tests/behat/filter_questions_combined_conditions.feature b/question/tests/behat/filter_questions_combined_conditions.feature
index 046d2550d8c..1afe2567611 100644
--- a/question/tests/behat/filter_questions_combined_conditions.feature
+++ b/question/tests/behat/filter_questions_combined_conditions.feature
@@ -14,10 +14,13 @@ Feature: The questions in the question bank can be filtered by combine various c
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
+ 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 1|
- | Course | C1 | Test questions 2|
+ | contextlevel | reference | name |
+ | Activity module | qbank1 | Test questions 1 |
+ | Activity module | qbank1 | Test questions 2 |
And the following "questions" exist:
| questioncategory | qtype | name | user | questiontext |
| Test questions 1 | essay | question 1 name | teacher1 | Question 1 text |
@@ -28,11 +31,12 @@ Feature: The questions in the question bank can be filtered by combine various c
| question | tag |
| question 1 name | foo |
| question 3 name | foo |
- And I am on the "Course 1" "core_question > course question bank" page logged in as "teacher1"
+ And I am on the "Qbank 1" "core_question > question bank" page logged in as "teacher1"
@javascript
Scenario: The questions can be filtered by matching all conditions
When I apply question bank filter "Category" with value "Test questions 1"
+ And I change window size to "large"
And I apply question bank filter "Tag" with value "foo"
Then I should see "question 1 name" in the "categoryquestions" "table"
And I should not see "question 2 name" in the "categoryquestions" "table"
diff --git a/question/tests/behat/question_categories.feature b/question/tests/behat/question_categories.feature
deleted file mode 100644
index ba147b8f1fb..00000000000
--- a/question/tests/behat/question_categories.feature
+++ /dev/null
@@ -1,39 +0,0 @@
-@core @core_question
-Feature: A teacher can move questions between categories in the question bank
- In order to organize my questions
- As a teacher
- I move questions between categories
-
- Background:
- Given the following "users" exist:
- | username | firstname | lastname | email |
- | teacher1 | Teacher | 1 | teacher1@example.com |
- And the following "courses" exist:
- | fullname | shortname | format |
- | Course 1 | C1 | weeks |
- And the following "course enrolments" exist:
- | user | course | role |
- | teacher1 | C1 | editingteacher |
- 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 |
- And the following "questions" exist:
- | questioncategory | qtype | name | questiontext |
- | Used category | essay | Test question to be moved | Write about whatever you want |
- And I log in as "teacher1"
- And I am on "Course 1" course homepage
-
- @javascript
- Scenario: Move a question between categories via the question page
- When I am on the "Course 1" "core_question > course question bank" page logged in as "teacher1"
- 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)" in the ".form-autocomplete-selection" "css_element"
diff --git a/question/tests/behat/question_categories_idnumber.feature b/question/tests/behat/question_categories_idnumber.feature
index f602a3e605c..e57c931683c 100644
--- a/question/tests/behat/question_categories_idnumber.feature
+++ b/question/tests/behat/question_categories_idnumber.feature
@@ -14,14 +14,17 @@ Feature: A teacher can put questions with idnumbers in categories in the questio
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 I log in as "teacher1"
And I am on "Course 1" course homepage
Scenario: A question can only have a unique idnumber within a category
When the following "question categories" exist:
- | contextlevel | reference | questioncategory | name | idnumber |
- | Course | C1 | Top | top | |
- | Course | C1 | top | Used category | c1used |
+ | contextlevel | reference | questioncategory | name | idnumber |
+ | Activity module | qbank1 | Top | top | |
+ | Activity module | qbank1 | top | Used category | c1used |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext | idnumber |
| Used category | essay | Test question 1 | Write about whatever you want | q1 |
@@ -34,9 +37,9 @@ Feature: A teacher can put questions with idnumbers in categories in the questio
Scenario: A question can be edited and saved without changing the idnumber
When the following "question categories" exist:
- | contextlevel | reference | questioncategory | name | idnumber |
- | Course | C1 | Top | top | |
- | Course | C1 | top | Used category | c1used |
+ | contextlevel | reference | questioncategory | name | idnumber |
+ | Activity module | qbank1 | Top | top | |
+ | Activity module | qbank1 | top | Used category | c1used |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext | idnumber |
| Used category | essay | Test question 1 | Write about whatever you want | q1 |
@@ -46,10 +49,10 @@ Feature: A teacher can put questions with idnumbers in categories in the questio
Scenario: Question idnumber conflicts found when saving to the same category.
When the following "question categories" exist:
- | contextlevel | reference | questioncategory | name |
- | Course | C1 | Top | top |
- | Course | C1 | top | Category 1 |
- | Course | C1 | top | Category 2 |
+ | contextlevel | reference | questioncategory | name |
+ | Activity module | qbank1 | Top | top |
+ | Activity module | qbank1 | top | Category 1 |
+ | Activity module | qbank1 | top | Category 2 |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext | idnumber |
| Category 1 | essay | Question to edit | Write about whatever you want | q1 |
@@ -62,10 +65,10 @@ Feature: A teacher can put questions with idnumbers in categories in the questio
@javascript
Scenario: Moving a question between categories can force a change to the idnumber
And the following "question categories" exist:
- | contextlevel | reference | questioncategory | name | idnumber |
- | Course | C1 | Top | top | |
- | Course | C1 | top | Subcategory | c1sub |
- | Course | C1 | top | Used category | c1used |
+ | contextlevel | reference | questioncategory | name | idnumber |
+ | Activity module | qbank1 | Top | top | |
+ | Activity module | qbank1 | top | Subcategory | c1sub |
+ | Activity module | qbank1 | top | Used category | c1used |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext | idnumber |
| Used category | essay | Test question 1 | Write about whatever you want | q1 |
@@ -79,8 +82,12 @@ Feature: A teacher can put questions with idnumbers in categories in the questio
And I click on "Test question 3" "checkbox" in the "Test question 3" "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"
+ And I open the autocomplete suggestions list in the ".search-categories" "css_element"
+ And I click on "Used category" 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
And I choose "Edit question" action for "Test question 3" in the question bank
# The question just moved into this category needs to have a unique idnumber, so a number is appended.
Then the field "ID number" matches value "q1_1"
diff --git a/question/tests/behat/question_filter_pagination.feature b/question/tests/behat/question_filter_pagination.feature
index 3af96c874eb..7bf60218558 100644
--- a/question/tests/behat/question_filter_pagination.feature
+++ b/question/tests/behat/question_filter_pagination.feature
@@ -14,9 +14,12 @@ Feature: A teacher can pagimate through question bank questions
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
+ 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 | questioncategory | name |
- | Course | C1 | Top | Used category |
+ | contextlevel | reference | questioncategory | name |
+ | Activity module | qbank1 | Top | Used category |
Given 100 "questions" exist with the following data:
| questioncategory | Used category |
| qtype | essay |
@@ -27,8 +30,8 @@ Feature: A teacher can pagimate through question bank questions
| Used category | essay | Not on first page | Write about whatever you want |
Scenario: Questions can be paginated
- When I am on the "Course 1" "core_question > course question bank" page logged in as "teacher1"
- When I apply question bank filter "Category" with value "Course 1"
+ Given I am on the "Qbank 1" "core_question > question bank" page logged in as "teacher1"
+ When I apply question bank filter "Category" with value "Top for Qbank 1"
And I follow "Sort by Question name ascending"
And I follow "Sort by Question name descending"
And I should see "Tests question 1"
diff --git a/question/tests/behat/question_highlight.feature b/question/tests/behat/question_highlight.feature
index 6b2c74bc501..6a114e17534 100644
--- a/question/tests/behat/question_highlight.feature
+++ b/question/tests/behat/question_highlight.feature
@@ -14,9 +14,12 @@ Feature: A teacher can see highlighted questions in the question bank
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 101 "questions" exist with the following data:
| questioncategory | Test questions |
| qtype | essay |
diff --git a/question/tests/behat/select_questions.feature b/question/tests/behat/select_questions.feature
index 3cde91b564f..5cded600472 100644
--- a/question/tests/behat/select_questions.feature
+++ b/question/tests/behat/select_questions.feature
@@ -14,15 +14,18 @@ Feature: The questions in the question bank can be selected in various ways
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
+ 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 | user | questiontext |
| Test questions | essay | A question 1 name | admin | Question 1 text |
| Test questions | essay | B question 2 name | teacher1 | Question 2 text |
| Test questions | numerical | C question 3 name | teacher1 | Question 3 text |
- And I am on the "Course 1" "core_question > course question bank" page logged in as "teacher1"
+ And I am on the "Qbank 1" "core_question > question bank" page logged in as "teacher1"
@javascript
Scenario: The question text can be chosen all in the list of questions
diff --git a/question/tests/behat/sort_questions.feature b/question/tests/behat/sort_questions.feature
index bab2f0ce6ca..03581e2f1ce 100644
--- a/question/tests/behat/sort_questions.feature
+++ b/question/tests/behat/sort_questions.feature
@@ -14,15 +14,18 @@ Feature: The questions in the question bank can be sorted in various ways
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
+ 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 | user | questiontext | idnumber |
| Test questions | essay | A question 1 name | admin | Question 1 text | numidnum course question bank" page logged in as "teacher1"
+ And I am on the "Qbank 1" "core_question > question bank" page logged in as "teacher1"
Scenario: The questions are sorted by type by default
Then "A question 1 name" "checkbox" should appear before "C question 3 name" "checkbox"
@@ -61,6 +64,7 @@ Feature: The questions in the question bank can be sorted in various ways
@javascript
Scenario: The question text can be shown in the list of questions
+ Given I change window size to "large"
When I set the field "Show question text in the question list?" to "Yes"
Then I should see "Question 1 text"
And I should see "Question 2 text"
diff --git a/question/tests/category_manager_test.php b/question/tests/category_manager_test.php
index 6ad6362c624..644ebb94c6a 100644
--- a/question/tests/category_manager_test.php
+++ b/question/tests/category_manager_test.php
@@ -31,6 +31,17 @@ use core_question\local\bank\question_edit_contexts;
* @covers \core_question\category_manager
*/
final class category_manager_test extends \advanced_testcase {
+
+ /**
+ * Create a course and qbank module and return the module context for use in tests.
+ *
+ * @return \core\context\module|false
+ */
+ private function create_course_and_get_qbank_context() {
+ $course = self::getDataGenerator()->create_course();
+ $qbank = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
+ return context_module::instance($qbank->cmid);
+ }
/**
* Test creating a category.
*/
@@ -39,7 +50,7 @@ final class category_manager_test extends \advanced_testcase {
$this->setAdminUser();
$this->resetAfterTest();
- $context = context_course::instance(SITEID);
+ $context = $this->create_course_and_get_qbank_context();
$topcat = question_get_top_category($context->id, true);
$manager = new category_manager();
$id = $manager->add_category(
@@ -63,7 +74,7 @@ final class category_manager_test extends \advanced_testcase {
$this->setAdminUser();
$this->resetAfterTest();
- $context = context_course::instance(SITEID);
+ $context = $this->create_course_and_get_qbank_context();
$topcat = question_get_top_category($context->id, true);
$manager = new category_manager();
$id = $manager->add_category(
@@ -87,7 +98,7 @@ final class category_manager_test extends \advanced_testcase {
$this->setAdminUser();
$this->resetAfterTest();
- $context = context_course::instance(SITEID);
+ $context = $this->create_course_and_get_qbank_context();
$topcat = question_get_top_category($context->id, true);
$manager = new category_manager();
$manager->add_category(
@@ -116,7 +127,7 @@ final class category_manager_test extends \advanced_testcase {
$this->setAdminUser();
$this->resetAfterTest();
- $context = context_course::instance(SITEID);
+ $context = $this->create_course_and_get_qbank_context();
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$topcat = question_get_top_category($context->id, true);
$category = $questiongenerator->create_question_category([
@@ -154,7 +165,7 @@ final class category_manager_test extends \advanced_testcase {
$this->setAdminUser();
$this->resetAfterTest();
- $context = context_course::instance(SITEID);
+ $context = $this->create_course_and_get_qbank_context();
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$topcat = question_get_top_category($context->id, true);
$category = $questiongenerator->create_question_category([
@@ -193,7 +204,7 @@ final class category_manager_test extends \advanced_testcase {
$this->setAdminUser();
$this->resetAfterTest();
- $context = context_course::instance(SITEID);
+ $context = $this->create_course_and_get_qbank_context();
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$topcat = question_get_top_category($context->id, true);
$category = $questiongenerator->create_question_category([
@@ -231,7 +242,7 @@ final class category_manager_test extends \advanced_testcase {
$this->setAdminUser();
$this->resetAfterTest();
- $context = context_course::instance(SITEID);
+ $context = $this->create_course_and_get_qbank_context();
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$topcat = question_get_top_category($context->id, true);
$questiongenerator->create_question_category([
@@ -304,7 +315,7 @@ final class category_manager_test extends \advanced_testcase {
$course = $generator->create_course();
$quiz = $generator->get_plugin_generator('mod_quiz')->create_instance(['course' => $course->id]);
$contexts = new question_edit_contexts(context_module::instance($quiz->cmid));
- $defaultcat = question_make_default_categories([$contexts->lowest()]);
+ $defaultcat = question_get_default_category($contexts->lowest()->id, true);
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
// Create the category.
$category = $questiongenerator->create_question_category([
@@ -381,7 +392,7 @@ final class category_manager_test extends \advanced_testcase {
$quiz = $generator->create_module('quiz', ['course' => $course->id]);
$contexts = new question_edit_contexts(context_module::instance($quiz->cmid));
- $defaultcategory = question_make_default_categories([$contexts->lowest()]);
+ $defaultcategory = question_get_default_category($contexts->lowest()->id, true);
$questiongerator = $generator->get_plugin_generator('core_question');
// Short answer question is made of one question.
@@ -406,7 +417,7 @@ final class category_manager_test extends \advanced_testcase {
$quiz = $generator->create_module('quiz', ['course' => $course->id]);
$contexts = new question_edit_contexts(context_module::instance($quiz->cmid));
- $defaultcategory = question_make_default_categories([$contexts->lowest()]);
+ $defaultcategory = question_get_default_category($contexts->lowest()->id, true);
$questiongerator = $generator->get_plugin_generator('core_question');
// Multi answer question is made of one parent and two child questions.
@@ -435,7 +446,7 @@ final class category_manager_test extends \advanced_testcase {
$quiz = $generator->create_module('quiz', ['course' => $course->id]);
$contexts = new question_edit_contexts(context_module::instance($quiz->cmid));
- $defaultcategory = question_make_default_categories([$contexts->lowest()]);
+ $defaultcategory = question_get_default_category($contexts->lowest()->id, true);
$questiongerator = $generator->get_plugin_generator('core_question');
// Create two versions of a multianswer question which will lead to
@@ -467,7 +478,7 @@ final class category_manager_test extends \advanced_testcase {
$quiz = $generator->create_module('quiz', ['course' => $course->id]);
$contexts = new question_edit_contexts(context_module::instance($quiz->cmid));
- $defaultcategory = question_make_default_categories([$contexts->lowest()]);
+ $defaultcategory = question_get_default_category($contexts->lowest()->id, true);
$questiongerator = $generator->get_plugin_generator('core_question');
// Multi answer question is made of one parent and two child questions.
@@ -507,7 +518,7 @@ final class category_manager_test extends \advanced_testcase {
$qcategory1 = $questiongenerator->create_question_category(['contextid' => $context->id]);
// Try to delete a top category.
- $categorytop = question_get_top_category($qcategory1->id, true)->id;
+ $categorytop = question_get_top_category($qcategory1->contextid, true)->id;
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('cannotdeletetopcat', 'question'));
$manager->require_can_delete_category($categorytop);
diff --git a/question/tests/generator/lib.php b/question/tests/generator/lib.php
index c9dd94b585c..e13906ba25a 100644
--- a/question/tests/generator/lib.php
+++ b/question/tests/generator/lib.php
@@ -74,7 +74,26 @@ class core_question_generator extends component_generator_base {
$qbank = $this->datagenerator->create_module('qbank', ['course' => SITEID]);
$record['contextid'] = context_module::instance($qbank->cmid)->id;
}
+ } else {
+ // Any requests for a question category in a contextlevel that is no longer supported
+ // will have a qbank instance created on the associated context and then the category
+ // will be made for that context instead.
+ $context = context::instance_by_id($record['contextid']);
+ if ($context->contextlevel !== CONTEXT_MODULE) {
+ $course = match ($context->contextlevel) {
+ CONTEXT_COURSE => get_course($context->instanceid),
+ CONTEXT_SYSTEM => get_site(),
+ CONTEXT_COURSECAT => $this->datagenerator->create_course(['category' => $context->instanceid]),
+ default => throw new \Exception('Invalid context to infer a question bank from.'),
+ };
+ $qbank = \core_question\local\bank\question_bank_helper::get_default_open_instance_system_type($course, true);
+ $bankcontext = context_module::instance($qbank->id);
+ } else {
+ $bankcontext = $context;
+ }
+ $record['contextid'] = $bankcontext->id;
}
+
if (!isset($record['parent'])) {
$record['parent'] = question_get_top_category($record['contextid'], true)->id;
}
diff --git a/question/tests/privacy/provider_test.php b/question/tests/privacy/provider_test.php
index a0b3519bcea..15325a06015 100644
--- a/question/tests/privacy/provider_test.php
+++ b/question/tests/privacy/provider_test.php
@@ -289,17 +289,18 @@ class provider_test extends \core_privacy\tests\provider_testcase {
$otheruser = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course();
- $context = \context_course::instance($course->id);
- $othercourse = $this->getDataGenerator()->create_course();
- $othercontext = \context_course::instance($othercourse->id);
+ $qbank1 = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
+ $qbank1context = \context_module::instance($qbank1->cmid);
+ $qbank2 = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
+ $qbank2context = \context_module::instance($qbank2->cmid);
// Create a couple of questions.
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$cat = $questiongenerator->create_question_category([
- 'contextid' => $context->id,
+ 'contextid' => $qbank1context->id,
]);
$othercat = $questiongenerator->create_question_category([
- 'contextid' => $othercontext->id,
+ 'contextid' => $qbank2context->id,
]);
// Create questions:
@@ -326,7 +327,7 @@ class provider_test extends \core_privacy\tests\provider_testcase {
$approvedcontextlist = new \core_privacy\tests\request\approved_contextlist(
$user,
'core_question',
- [$context->id]
+ [$qbank1context->id]
);
// Find out how many questions are in the question bank to start with.
@@ -370,17 +371,18 @@ class provider_test extends \core_privacy\tests\provider_testcase {
$otheruser = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course();
- $context = \context_course::instance($course->id);
- $othercourse = $this->getDataGenerator()->create_course();
- $othercontext = \context_course::instance($othercourse->id);
+ $qbank1 = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
+ $qbank1context = \context_module::instance($qbank1->cmid);
+ $qbank2 = self::getDataGenerator()->create_module('qbank', ['course' => $course->id]);
+ $qbank2context = \context_module::instance($qbank2->cmid);
// Create a couple of questions.
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$cat = $questiongenerator->create_question_category([
- 'contextid' => $context->id,
+ 'contextid' => $qbank1context->id,
]);
$othercat = $questiongenerator->create_question_category([
- 'contextid' => $othercontext->id,
+ 'contextid' => $qbank2context->id,
]);
// Create questions:
@@ -407,7 +409,7 @@ class provider_test extends \core_privacy\tests\provider_testcase {
// Delete the data and check it is removed.
$this->setUser();
- provider::delete_data_for_all_users_in_context($context);
+ provider::delete_data_for_all_users_in_context($qbank1context);
$this->assertEquals($questioncount, $DB->count_records('question'));
diff --git a/question/tests/question_bank_column_test.php b/question/tests/question_bank_column_test.php
index e659a76d12a..d2d90dd5e62 100644
--- a/question/tests/question_bank_column_test.php
+++ b/question/tests/question_bank_column_test.php
@@ -42,10 +42,13 @@ class question_bank_column_test extends \advanced_testcase {
public function test_column_header_multi_sort_no_tooltips(): void {
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
+ $qbank = $this->getDataGenerator()->create_module('qbank', ['course' => $course->id]);
+ $cm = get_coursemodule_from_id('qbank', $qbank->cmid);
$questionbank = new view(
new question_edit_contexts(\context_course::instance($course->id)),
new \moodle_url('/'),
- $course
+ $course,
+ $cm
);
$columnbase = new testable_core_question_column($questionbank);
@@ -76,10 +79,13 @@ class question_bank_column_test extends \advanced_testcase {
public function test_column_header_multi_sort_with_tooltips(): void {
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
+ $qbank = $this->getDataGenerator()->create_module('qbank', ['course' => $course->id]);
+ $cm = get_coursemodule_from_id('qbank', $qbank->cmid);
$questionbank = new view(
new question_edit_contexts(\context_course::instance($course->id)),
new \moodle_url('/'),
- $course
+ $course,
+ $cm
);
$columnbase = new testable_core_question_column($questionbank);
diff --git a/question/type/calculated/tests/question_type_test.php b/question/type/calculated/tests/question_type_test.php
index e10a8fc91f8..4cc45367adf 100644
--- a/question/type/calculated/tests/question_type_test.php
+++ b/question/type/calculated/tests/question_type_test.php
@@ -105,7 +105,7 @@ class question_type_test extends \advanced_testcase {
$this->assertEquals($question->createdby, $questiondata->createdby);
$this->assertEquals($question->createdby, $questiondata->modifiedby);
$this->assertEquals('', $questiondata->idnumber);
- $this->assertEquals($syscontext->id, $questiondata->contextid);
+ $this->assertEquals($category->contextid, $questiondata->contextid);
$this->assertEquals([], $questiondata->hints);
// Options.
diff --git a/question/type/essay/tests/restore_test.php b/question/type/essay/tests/restore_test.php
index 630a9eaa145..377bdf0a95e 100644
--- a/question/type/essay/tests/restore_test.php
+++ b/question/type/essay/tests/restore_test.php
@@ -63,7 +63,7 @@ class restore_test extends \restore_date_testcase {
$newqbank = reset($newqbanks);
// Verify that the restored question has options.
- $newcategory = question_make_default_category(\context_module::instance($newqbank->id));
+ $newcategory = question_get_default_category(\context_module::instance($newqbank->id)->id, true);
$newessay = $DB->get_record_sql('SELECT q.*
FROM {question} q
JOIN {question_versions} qv ON qv.questionid = q.id
diff --git a/question/type/gapselect/tests/behat/import_test.feature b/question/type/gapselect/tests/behat/import_test.feature
index 572ffc0e216..dfdcd5ecc47 100644
--- a/question/type/gapselect/tests/behat/import_test.feature
+++ b/question/type/gapselect/tests/behat/import_test.feature
@@ -31,6 +31,7 @@ Feature: Import and export select missing words questions
# Now export again.
And I am on the "Course 1" "core_question > course question export" page logged in as teacher
And I set the field "id_format_xml" to "1"
+ And I set the field "Export category" to "Default for C1 (1)"
And I press "Export questions to file"
And following "click here" should download a file that:
| Has mimetype | text/xml |
diff --git a/question/type/multianswer/tests/question_type_test.php b/question/type/multianswer/tests/question_type_test.php
index 6c25c8ea658..bdb6d134af9 100644
--- a/question/type/multianswer/tests/question_type_test.php
+++ b/question/type/multianswer/tests/question_type_test.php
@@ -192,7 +192,7 @@ class question_type_test extends \advanced_testcase {
$this->assertEquals($question->createdby, $questiondata->createdby);
$this->assertEquals($question->createdby, $questiondata->modifiedby);
$this->assertEquals('', $questiondata->idnumber);
- $this->assertEquals($syscontext->id, $questiondata->contextid);
+ $this->assertEquals($category->contextid, $questiondata->contextid);
// Build the expected hint base.
$hintbase = [
diff --git a/question/type/questiontypebase.php b/question/type/questiontypebase.php
index 78f585d7f4d..1adbe0265ad 100644
--- a/question/type/questiontypebase.php
+++ b/question/type/questiontypebase.php
@@ -1396,7 +1396,9 @@ class question_type {
* required to set up and save a question of any type for testing purposes.
* Alternate DB table prefix may be used to facilitate data deletion.
*/
+ #[\core\attribute\deprecated(replacement: null, since: '5.0', mdl: 'MDL-71378')]
public function generate_test($name, $courseid=null) {
+ \core\deprecation::emit_deprecation_if_present([$this, __FUNCTION__]);
$form = new stdClass();
$form->name = $name;
$form->questiontextformat = 1;
diff --git a/question/type/truefalse/tests/question_type_test.php b/question/type/truefalse/tests/question_type_test.php
index 43e035ddeb8..ab4075df97d 100644
--- a/question/type/truefalse/tests/question_type_test.php
+++ b/question/type/truefalse/tests/question_type_test.php
@@ -100,7 +100,7 @@ class question_type_test extends \advanced_testcase {
$this->assertEquals($question->createdby, $questiondata->createdby);
$this->assertEquals($question->createdby, $questiondata->modifiedby);
$this->assertEquals('', $questiondata->idnumber);
- $this->assertEquals($syscontext->id, $questiondata->contextid);
+ $this->assertEquals($category->contextid, $questiondata->contextid);
// Options.
$this->assertEquals($questiondata->id, $questiondata->options->question);
diff --git a/report/questioninstances/tests/behat/question_reports.feature b/report/questioninstances/tests/behat/question_reports.feature
index 4c7e57e7724..bd249365680 100644
--- a/report/questioninstances/tests/behat/question_reports.feature
+++ b/report/questioninstances/tests/behat/question_reports.feature
@@ -11,12 +11,12 @@ Feature: A Teacher can generate question instance reports
And the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | weeks |
- And the following "question categories" exist:
- | contextlevel | reference | name |
- | Course | C1 | Test questions |
And the following "activities" exist:
| activity | course | name |
| quiz | C1 | Test quiz Q001 |
+ And the following "question categories" exist:
+ | contextlevel | reference | name |
+ | Activity module | Test quiz Q001 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name |
| Test questions | truefalse | TF |
@@ -36,9 +36,9 @@ Feature: A Teacher can generate question instance reports
Given I am on the "C1" "Course" page logged in as "admin"
And I navigate to "Reports > Question instances" in site administration
When I press "Get the report"
- Then "Course: Course 1" row "Total" column of "generaltable" table should contain "2"
- And "Course: Course 1" row "Visible" column of "generaltable" table should contain "2"
- And "Course: Course 1" row "Hidden" column of "generaltable" table should contain "0"
+ Then "Quiz: Test quiz Q001" row "Total" column of "generaltable" table should contain "2"
+ And "Quiz: Test quiz Q001" row "Visible" column of "generaltable" table should contain "2"
+ And "Quiz: Test quiz Q001" row "Hidden" column of "generaltable" table should contain "0"
Scenario: Generate report displaying hidden questions
Given I am on the "Test quiz Q001" "mod_quiz > question bank" page logged in as "admin"
@@ -46,11 +46,11 @@ Feature: A Teacher can generate question instance reports
And I press "Delete"
And I navigate to "Reports > Question instances" in site administration
When I press "Get the report"
- Then "Course: Course 1" row "Total" column of "generaltable" table should contain "2"
- And "Course: Course 1" row "Visible" column of "generaltable" table should contain "1"
- And "Course: Course 1" row "Hidden" column of "generaltable" table should contain "1"
+ Then "Quiz: Test quiz Q001" row "Total" column of "generaltable" table should contain "2"
+ And "Quiz: Test quiz Q001" row "Visible" column of "generaltable" table should contain "1"
+ And "Quiz: Test quiz Q001" row "Hidden" column of "generaltable" table should contain "1"
And I set the field "menuqtype" to "True/False"
And I press "Get the report"
- And "Course: Course 1" row "Total" column of "generaltable" table should contain "1"
- And "Course: Course 1" row "Visible" column of "generaltable" table should contain "0"
- And "Course: Course 1" row "Hidden" column of "generaltable" table should contain "1"
+ And "Quiz: Test quiz Q001" row "Total" column of "generaltable" table should contain "1"
+ And "Quiz: Test quiz Q001" row "Visible" column of "generaltable" table should contain "0"
+ And "Quiz: Test quiz Q001" row "Hidden" column of "generaltable" table should contain "1"
diff --git a/theme/classic/tests/behat/behat_theme_classic_behat_core_question.php b/theme/classic/tests/behat/behat_theme_classic_behat_core_question.php
index e0885ef989b..b933916904e 100644
--- a/theme/classic/tests/behat/behat_theme_classic_behat_core_question.php
+++ b/theme/classic/tests/behat/behat_theme_classic_behat_core_question.php
@@ -35,15 +35,10 @@ class behat_theme_classic_behat_core_question extends behat_core_question {
* @param string $questiontypename The question type name
* @param TableNode $questiondata The data to fill the question type form.
*/
+ #[\core\attribute\deprecated('behat_core_question::i_add_a_question_filling_the_form_with()', since: '5.0', mdl: 'MDL-71378')]
public function i_add_a_question_filling_the_form_with($questiontypename, TableNode $questiondata) {
- // Go to question bank.
- $this->execute("behat_general::click_link", get_string('questionbank', 'question'));
-
- // Click on create question.
- $this->execute('behat_forms::press_button', get_string('createnewquestion', 'question'));
-
- // Add question.
- $this->finish_adding_question($questiontypename, $questiondata);
+ \core\deprecation::emit_deprecation_if_present([$this, __FUNCTION__]);
+ parent::i_add_a_question_filling_the_form_with($questiontypename, $questiondata);
}
}