diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ce3aa65
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+phpunit.xml
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..343a26c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,59 @@
+# Question to activity - A Moodle Question Bank Plugin
+
+## Description
+Question to activity (qtoactivity) is a plugin for the Moodle LMS that extends the functionality of the question bank question management page.
+This plugin adds the option for users to select individual or multiple questions and add them right to an activity of their choosing, without having to access that individual activities management page.
+
+---
+
+## Installation instructions
+_Follow these steps to install Question to activity:_
+1. Download the plugin to the ___{moodle directory}/question/bank/___ directory as a new folder called ___qtoactivity___. This can be done in either of the following ways:
+ - With Git from within the _/question/bank_ directory, running the following command:
+ ```
+ git clone https://github.com/safatshahin/moodle-qbank_qtoactivity
+ ```
+ - Or by downloading the code manually from https://github.com/safatshahin/moodle-qbank_qtoactivity and extracting it to the _question/bank/qtoactivity_ directory.
+
+2. Access the Admin Dashboard from your Moodle site to automatically trigger the install, or use the cli.
+
+---
+
+## Usage
+To use the plugin, simply navigate to the question bank question management page and do either of the following:
+
+### Individual questions
+- You can choose to add a single question to an activity by selecting the __Add to module__ option from the actions column. Follow the on-screen instructions to select the activity to add the question to.
+
+### Multiple questions
+- You can choose to add multiple questions to an activity by first selecting the check boxes of the questions you wish to add, and then choosing the __Add to module__ option from the bulk actions drop down beneath the list of questions. Follow the on-screen instructions to select the activity to add the questions to.
+
+---
+
+
+
+# Credits and thanks
+
+## Project information
+This project was initially started as part of a student project collaboration with Catalyst IT Australia and University of New England.
+The main goal of this project was to help students prepare for the industry by having a mentor from the host company, coming up with a project idea
+and finally create an mvp of the idea using industry approach and methodologies. This project was a huge success where all the students were able to
+learn and develop an mvp of the qbank plugin and showcase their work to the university.
+
+Project manager:
+- A K M Safat Shahin - safatshahin@yahoo.com
+
+Team members from University of new England:
+- Mark Hay - mhay23@myune.edu.au
+- Henry Campbell - hcampb25@myune.edu.au
+- Luke Purnell - lpurnell@myune.edu.au
+- Harrison Liddell - hliddell@myune.edu.au
+
+## Project enhancement
+The initial product was done in a short timeframe and proved that the idea is possible and students gained a real experience of the industry.
+To make this project usable and available to the community, a lot of work needed to be done on top of the great work from the students.
+The current phase took advantage of the initial development, polished the code and changed it to allow a better future and follow the proper
+moodle way of doing plugins.
+
+---
+
diff --git a/addtoactivity.php b/addtoactivity.php
new file mode 100644
index 0000000..5e93c3a
--- /dev/null
+++ b/addtoactivity.php
@@ -0,0 +1,107 @@
+.
+
+/**
+ * Add to activity page.
+ *
+ * @package qbank_qtoactivity
+ * @copyright 2023 Safat Shahin
+ * @author Luke Purnel, Henry Campbell, Mark Hay, Harrison Liddell
+ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+global $CFG, $OUTPUT, $PAGE, $COURSE;
+
+require_once(__DIR__ . '/../../../config.php');
+require_once($CFG->dirroot . '/question/editlib.php');
+
+$addtomoduleselected = optional_param('addtomoduleselected', false, PARAM_BOOL);
+$returnurl = optional_param('returnurl', 0, PARAM_LOCALURL);
+$cmid = optional_param('cmid', 0, PARAM_INT);
+$courseid = optional_param('courseid', 0, PARAM_INT);
+$confirm = optional_param('confirm', '', PARAM_ALPHANUM);
+$addtomodule = optional_param('addtomodule', null, PARAM_INT);
+$addtomodulesquestions = optional_param('addtomodulesquestions', null, PARAM_RAW);
+
+if ($returnurl) {
+ $returnurl = new moodle_url($returnurl);
+}
+
+// Check if plugin is enabled or not.
+\core_question\local\bank\helper::require_plugin_enabled('qbank_qtoactivity');
+
+if ($cmid) {
+ list($module, $cm) = get_module_from_cmid($cmid);
+ require_login($cm->course, false, $cm);
+ $thiscontext = context_module::instance($cmid);
+ $modules = \qbank_qtoactivity\helper::get_module($cmid);
+} else if ($courseid) {
+ require_login($courseid, false);
+ $thiscontext = context_course::instance($courseid);
+ $modules = \qbank_qtoactivity\helper::get_modules_for_course($courseid);
+} else {
+ throw new moodle_exception('missingcourseorcmid', 'question');
+}
+
+$contexts = new core_question\local\bank\question_edit_contexts($thiscontext);
+$url = new moodle_url('/question/bank/qtoactivity/addtoactivity.php');
+$title = get_string('addtomodule', 'qbank_qtoactivity');
+
+// Context and page setup.
+$PAGE->set_url($url);
+$PAGE->set_title($title);
+$PAGE->set_heading($COURSE->fullname);
+$PAGE->set_pagelayout('standard');
+$PAGE->activityheader->disable();
+$PAGE->set_secondary_active_tab("questionbank");
+
+
+
+if ($addtomodulesquestions && $confirm && confirm_sesskey()) {
+ if ($confirm == md5($addtomodulesquestions)) {
+ \qbank_qtoactivity\helper::add_to_module($addtomodulesquestions, $addtomodule);
+ }
+ redirect($returnurl);
+}
+
+// Show the header.
+echo $OUTPUT->header();
+
+
+
+if ($addtomoduleselected) {
+ $rawquestions = $_REQUEST;
+ list($questionids, $questionlist) = \qbank_qtoactivity\helper::process_question_ids($rawquestions);
+ // No questions were selected.
+ if (!$questionids) {
+ redirect($returnurl);
+ }
+ // Create the urls.
+ $addtomoduleparams = [
+ 'addtomodulesquestions' => $questionlist,
+ 'confirm' => md5($questionlist),
+ 'sesskey' => sesskey(),
+ 'returnurl' => $returnurl,
+ 'cmid' => $cmid,
+ 'courseid' => $courseid,
+ ];
+ $addtomoduleurl = new \moodle_url($url, $addtomoduleparams);
+ echo $PAGE->get_renderer('qbank_qtoactivity')
+ ->render_add_to_module_form($addtomoduleurl, $returnurl, $modules);
+}
+
+// Show the footer.
+echo $OUTPUT->footer();
diff --git a/classes/add_action_column.php b/classes/add_action_column.php
new file mode 100644
index 0000000..34b5720
--- /dev/null
+++ b/classes/add_action_column.php
@@ -0,0 +1,66 @@
+.
+
+namespace qbank_qtoactivity;
+
+use core_question\local\bank\menu_action_column_base;
+
+/**
+ * Adds a single action titled 'Add to Quiz' to the actions menu.
+ *
+ * @package qbank_qtoactivity
+ * @copyright 2023 Safat Shahin
+ * @author Luke Purnel, Henry Campbell, Mark Hay, Harrison Liddell
+ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class add_action_column extends menu_action_column_base {
+
+ /**
+ * Array of the return parameters.
+ * @var array $returnparams
+ */
+ protected $returnparams;
+
+ public function init(): void {
+ parent::init();
+ 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;
+ }
+ if (!empty($this->qbank->returnurl)) {
+ $this->returnparams['returnurl'] = $this->qbank->returnurl;
+ }
+ }
+
+ public function get_name(): string {
+ return 'addtomoduleaction';
+ }
+
+ protected function get_url_icon_and_label(\stdClass $question): array {
+ $params = [
+ 'addtomoduleselected' => $question->id,
+ 'q' . $question->id => 1,
+ 'sesskey' => sesskey()
+ ];
+ $addtomoduleparams = array_merge($params, $this->returnparams);
+ $url = new \moodle_url('/question/bank/qtoactivity/addtoactivity.php', $addtomoduleparams);
+
+ return [$url, 't/add', get_string('addtomodule', 'qbank_qtoactivity')];
+ }
+
+}
diff --git a/classes/bulk_add_action.php b/classes/bulk_add_action.php
new file mode 100644
index 0000000..ca7d7b7
--- /dev/null
+++ b/classes/bulk_add_action.php
@@ -0,0 +1,46 @@
+.
+
+namespace qbank_qtoactivity;
+
+/**
+ * Class for 'Add to activity' bulk action.
+ *
+ * @package qbank_qtoactivity
+ * @copyright 2023 Safat Shahin
+ * @author Luke Purnel, Henry Campbell, Mark Hay, Harrison Liddell
+ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class bulk_add_action extends \core_question\local\bank\bulk_action_base {
+
+ public function get_bulk_action_title(): string {
+ return get_string('addtomodule', 'qbank_qtoactivity');
+ }
+
+ public function get_bulk_action_url(): \moodle_url {
+ return new \moodle_url('/question/bank/qtoactivity/addtoactivity.php');
+ }
+
+ public function get_bulk_action_capabilities(): ?array {
+ return [
+ 'moodle/question:editall',
+ ];
+ }
+
+ public function get_key(): string {
+ return 'addtomoduleselected';
+ }
+}
diff --git a/classes/helper.php b/classes/helper.php
new file mode 100644
index 0000000..f0a8fd1
--- /dev/null
+++ b/classes/helper.php
@@ -0,0 +1,124 @@
+.
+
+namespace qbank_qtoactivity;
+
+/**
+ * Helper class for question to activity plugin which includes all the associated methods.
+ *
+ * @package qbank_qtoactivity
+ * @copyright 2023 Safat Shahin
+ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class helper {
+
+ /**
+ * Get the module info from cm id.
+ *
+ * @param int $cmid The id of the module
+ * @return array
+ */
+ public static function get_module(int $cmid): array {
+ // TODO think of a way to add the module logo.
+ [$modrec, $cmrec] = get_module_from_cmid($cmid);
+ $modulearray[$cmid] = $cmrec->name;
+ return $modulearray;
+ }
+
+ /**
+ * Gets a list of modules for a given course.
+ *
+ * @param int $courseid The ID of the given course
+ * @return array An array of all the quizzes
+ */
+ public static function get_modules_for_course(int $courseid): array {
+ $modules = [];
+ $course = get_course($courseid);
+ $courseactivities = \course_modinfo::get_array_of_activities($course, true);
+
+ foreach ($courseactivities as $courseactivity) {
+ // Add support for quiz activity.
+ // TODO think of a better way to get the list of activities using or extending the question bank api.
+ if ($courseactivity->mod === "quiz") {
+ $modules[$courseactivity->cm] = $courseactivity->name;
+ }
+ }
+
+ return $modules;
+ }
+
+ /**
+ * Process the question came from the form post.
+ *
+ * @param array $rawquestions raw questions came as a part of post.
+ * @return array question ids got from the post are processed and structured in an array.
+ */
+ public static function process_question_ids(array $rawquestions): array {
+ $questionids = [];
+ $questionlist = '';
+ foreach ($rawquestions as $key => $notused) {
+ // Parse input for question ids.
+ if (preg_match('!^q([0-9]+)$!', $key, $matches)) {
+ $key = $matches[1];
+ $questionids[] = $key;
+ }
+ }
+ if (!empty($questionids)) {
+ $questionlist = implode(',', $questionids);
+ }
+ return [$questionids, $questionlist];
+ }
+
+ /**
+ * Add question to the module.
+ *
+ * @param string $addtomoduleselected The selection question ids
+ * @param int $addtomodule The selected module
+ * @return void
+ */
+ public static function add_to_module(string $addtomoduleselected, int $addtomodule): void {
+ global $DB;
+ if ($questionids = explode(',', $addtomoduleselected)) {
+ list($usql, $params) = $DB->get_in_or_equal($questionids);
+ $sql = "SELECT q.*, c.contextid
+ 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} c ON c.id = qbe.questioncategoryid
+ WHERE q.id
+ {$usql}";
+ $questions = $DB->get_records_sql($sql, $params);
+ [$module, $cmrec] = get_module_from_cmid($addtomodule);
+ if ($cmrec->modname === 'quiz') {
+ self::question_add_to_quiz_avtivity($questions, $module);
+ }
+ }
+ }
+
+ /**
+ * @param array $questions The questions to be added
+ * @param \stdClass $quiz The quiz object
+ * @return void
+ */
+ public static function question_add_to_quiz_avtivity(array $questions, \stdClass $quiz): void {
+ global $CFG;
+ require_once($CFG->dirroot . '/mod/quiz/locallib.php');
+ foreach ($questions as $question) {
+ quiz_add_quiz_question($question->id, $quiz);
+ }
+ }
+
+}
diff --git a/classes/output/form/add_to_module_form.php b/classes/output/form/add_to_module_form.php
new file mode 100644
index 0000000..51ba253
--- /dev/null
+++ b/classes/output/form/add_to_module_form.php
@@ -0,0 +1,40 @@
+.
+
+namespace qbank_qtoactivity\output\form;
+
+defined('MOODLE_INTERNAL') || die();
+global $CFG;
+require_once($CFG->dirroot . '/lib/formslib.php');
+require_once($CFG->dirroot . '/lib/grouplib.php');
+require_once($CFG->dirroot . '/lib/datalib.php');
+
+/**
+ * Add to module form to populate the available modules in the context.
+ *
+ * @package qbank_qtoactivity
+ * @copyright 2023 Safat Shahin
+ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class add_to_module_form extends \moodleform {
+
+ protected function definition() {
+ $mform = $this->_form;
+ $modules = $this->_customdata['modules'];
+
+ $mform->addElement('select', 'addtomodule', get_string('select_activity', 'qbank_qtoactivity'), $modules);
+ }
+}
diff --git a/classes/output/renderer.php b/classes/output/renderer.php
new file mode 100644
index 0000000..3e9f876
--- /dev/null
+++ b/classes/output/renderer.php
@@ -0,0 +1,53 @@
+.
+
+namespace qbank_qtoactivity\output;
+
+/**
+ * Renderer for the question to activity.
+ *
+ * @package qbank_qtoactivity
+ * @copyright 2023 Safat Shahin
+ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class renderer extends \plugin_renderer_base {
+
+ /**
+ * Renderer for module form.
+ *
+ * @param \moodle_url $addtomoduleurl Add to module url
+ * @param \moodle_url $returnurl The return url to question bank
+ * @param array $modules The array of modules
+ * @return string
+ */
+ public function render_add_to_module_form(\moodle_url $addtomoduleurl, \moodle_url $returnurl, array $modules): string {
+ $displaydata = [];
+ $displaydata['returnurl'] = $returnurl;
+ $displaydata['modules'] = false;
+
+ if (!empty($modules)) {
+ // Module selection form.
+ $addtomoduleform = new \qbank_qtoactivity\output\form\add_to_module_form(null, ['modules' => $modules]);
+
+ $displaydata['modules'] = true;
+ $displaydata['moduledropdown'] = $addtomoduleform->render();
+ $displaydata['addtomoduleurl'] = $addtomoduleurl;
+ }
+
+ return $this->render_from_template('qbank_qtoactivity/add_to_activity_form', $displaydata);
+ }
+
+}
diff --git a/classes/plugin_feature.php b/classes/plugin_feature.php
new file mode 100644
index 0000000..d948e75
--- /dev/null
+++ b/classes/plugin_feature.php
@@ -0,0 +1,42 @@
+.
+
+namespace qbank_qtoactivity;
+
+use core_question\local\bank\plugin_features_base;
+
+/**
+ * Adds question to activity bulk action in the bulk actions list.
+ *
+ * @package qbank_qtoactivity
+ * @copyright 2023 Safat Shahin
+ * @author Luke Purnel, Henry Campbell, Mark Hay, Harrison Liddell
+ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class plugin_feature extends plugin_features_base {
+
+ public function get_question_columns($qbank): array {
+ return [
+ new add_action_column($qbank),
+ ];
+ }
+
+ public function get_bulk_actions(): array {
+ return [
+ new bulk_add_action()
+ ];
+ }
+}
diff --git a/classes/privacy/provider.php b/classes/privacy/provider.php
new file mode 100644
index 0000000..96d724c
--- /dev/null
+++ b/classes/privacy/provider.php
@@ -0,0 +1,32 @@
+.
+
+namespace qbank_qtoactivity\privacy;
+
+/**
+ * Privacy subsystem for qbank_qtoactivity that implements a null provider
+ *
+ * @package qbank_qtoactivity
+ * @copyright 2023 Safat Shahin
+ * @author Luke Purnel, Henry Campbell, Mark Hay, Harrison Liddell
+ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+ public static function get_reason(): string {
+ return 'privacy:metadata';
+ }
+}
diff --git a/lang/en/qbank_qtoactivity.php b/lang/en/qbank_qtoactivity.php
new file mode 100644
index 0000000..9679b6b
--- /dev/null
+++ b/lang/en/qbank_qtoactivity.php
@@ -0,0 +1,34 @@
+.
+
+/**
+ * Plugin strings for question to activity, lang 'en'.
+ *
+ * @package qbank_qtoactivity
+ * @copyright 2023 Safat Shahin
+ * @author Luke Purnel, Henry Campbell, Mark Hay, Harrison Liddell
+ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['addtomodule'] = "Add to module";
+$string['addtoquizinstruction'] = "Select the quiz to add questions to:";
+$string['cancel_add_to_module'] = 'Cancel';
+$string['noactivityfound'] = 'No activity found.';
+$string['pluginname'] = 'Question to activity';
+$string['privacy:metadata'] = 'Question to activity plugin does not store any user data.';
+$string['select_activity'] = 'Select an activity';
diff --git a/templates/add_to_activity_form.mustache b/templates/add_to_activity_form.mustache
new file mode 100644
index 0000000..48d19df
--- /dev/null
+++ b/templates/add_to_activity_form.mustache
@@ -0,0 +1,36 @@
+{{!
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Moodle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Moodle. If not, see .
+}}
+
+
+
+{{^modules}}
+
+{{/modules}}
+{{#modules}}
+
+
+{{/modules}}
diff --git a/tests/behat/question_to_activity.feature b/tests/behat/question_to_activity.feature
new file mode 100644
index 0000000..8584a7b
--- /dev/null
+++ b/tests/behat/question_to_activity.feature
@@ -0,0 +1,46 @@
+@qbank @qbank_question_to_activity @javascript
+Feature: Use the qbank plugin manager page for question to activity
+ In order to check the plugin behaviour with enable and disable
+
+ Background:
+ Given the following "courses" exist:
+ | fullname | shortname | category |
+ | Course 1 | C1 | 0 |
+ And the following "activities" exist:
+ | activity | name | course | idnumber |
+ | quiz | Test quiz | C1 | quiz1 |
+ 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 |
+
+ @javascript
+ Scenario: Enable/disable question to activity bulk action from the base view
+ Given I log in as "admin"
+ When I navigate to "Plugins > Question bank plugins > Manage question bank plugins" in site administration
+ And I should see "Question to activity"
+ And I click on "Disable" "link" in the "Question to activity" "table_row"
+ And I am on the "Test quiz" "mod_quiz > question bank" page
+ And I click on "First question" "checkbox"
+ And I click on "With selected" "button"
+ Then I should not see question bulk action "addtomoduleselected"
+ And I navigate to "Plugins > Question bank plugins > Manage question bank plugins" in site administration
+ And I click on "Enable" "link" in the "Question to activity" "table_row"
+ And I am on the "Test quiz" "mod_quiz > question bank" page
+ And I click on "First question" "checkbox"
+ And I click on "With selected" "button"
+ And I should see question bulk action "addtomoduleselected"
+
+ Scenario: Enable/disable question to activity column from the base view
+ Given I log in as "admin"
+ When I navigate to "Plugins > Question bank plugins > Manage question bank plugins" in site administration
+ And I should see "Question to activity"
+ And I click on "Disable" "link" in the "Question to activity" "table_row"
+ And I am on the "Test quiz" "mod_quiz > question bank" page
+ Then the "Add to module" action should not exist for the "First question" question in the question bank
+ And I navigate to "Plugins > Question bank plugins > Manage question bank plugins" in site administration
+ And I click on "Enable" "link" in the "Question to activity" "table_row"
+ And I am on the "Test quiz" "mod_quiz > question bank" page
+ And the "Add to module" action should exist for the "First question" question in the question bank
diff --git a/tests/helper_test.php b/tests/helper_test.php
new file mode 100644
index 0000000..ed59e8d
--- /dev/null
+++ b/tests/helper_test.php
@@ -0,0 +1,162 @@
+.
+
+namespace qbank_qtoactivity;
+
+use core_question\local\bank\question_edit_contexts;
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/question/editlib.php');
+
+/**
+ * Question to activity helper tests.
+ *
+ * @package qbank_qtoactivity
+ * @copyright 2023 Safat Shahin
+ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @coversDefaultClass \qbank_qtoactivity\helper
+ */
+class helper_test extends \advanced_testcase {
+
+ /**
+ * @var \stdClass $questiondata1
+ */
+ protected $questiondata1;
+
+ /**
+ * @var \stdClass $questiondata2
+ */
+ protected $questiondata2;
+
+ /**
+ * @var array $rawdata
+ */
+ protected $rawdata;
+
+ /**
+ * Test bulk move of questions.
+ *
+ * @covers ::add_to_module
+ * @covers ::question_add_to_quiz_avtivity
+ */
+ public function test_add_to_module() {
+ $this->resetAfterTest();
+ $this->setAdminUser();
+ $generator = $this->getDataGenerator();
+ /** @var \core_question_generator $questiongenerator */
+ $questiongenerator = $generator->get_plugin_generator('core_question');
+
+ // Create a course.
+ $course = $generator->create_course();
+ $context = \context_course::instance($course->id);
+
+ // Create question in the default category.
+ $contexts = new question_edit_contexts($context);
+ $cat = question_make_default_categories($contexts->all());
+ $this->questiondata1 = $questiongenerator->create_question('numerical', null,
+ ['name' => 'Example question', 'category' => $cat->id]);
+
+ // Ensure the question is not in the cache.
+ $cache = \cache::make('core', 'questiondata');
+ $cache->delete($this->questiondata1->id);
+
+ $this->questiondata2 = $questiongenerator->create_question('numerical', null,
+ ['name' => 'Example question second', 'category' => $cat->id]);
+
+ // Ensure the question is not in the cache.
+ $cache = \cache::make('core', 'questiondata');
+ $cache->delete($this->questiondata2->id);
+
+ // Posted raw data.
+ $this->rawdata = [
+ 'courseid' => $course->id,
+ 'cat' => "{$cat->id},{$context->id}",
+ 'qpage' => '0',
+ "q{$this->questiondata1->id}" => '1',
+ "q{$this->questiondata2->id}" => '1',
+ ];
+
+ // Get the processed question ids.
+ $questionlist = $this->process_question_ids_test();
+
+ // Create a quiz.
+ /** @var \mod_quiz_generator $quizgenerator */
+ $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
+ $quiz = $quizgenerator->create_instance([
+ 'course' => $course->id,
+ 'questionsperpage' => 0,
+ 'grade' => 100.0,
+ 'sumgrades' => 2,
+ ]);
+ $quizcontext = \context_module::instance($quiz->cmid);
+
+ helper::add_to_module($questionlist, $quiz->cmid);
+
+ $this->assertCount(2, \mod_quiz\question\bank\qbank_helper::get_question_structure($quiz->id, $quizcontext));
+ }
+
+ /**
+ * Test the question processing and return the question list.
+ *
+ * @return string
+ * @covers ::process_question_ids
+ */
+ protected function process_question_ids_test(): string {
+ // Test the raw data processing.
+ list($questionids, $questionlist) = helper::process_question_ids($this->rawdata);
+ $this->assertEquals([$this->questiondata1->id, $this->questiondata2->id], $questionids);
+ $this->assertEquals("{$this->questiondata1->id},{$this->questiondata2->id}", $questionlist);
+ return $questionlist;
+ }
+
+ /**
+ * Test get module for course only gets quiz.
+ *
+ * @covers ::get_modules_for_course
+ */
+ public function test_get_modules_for_course() {
+ $this->resetAfterTest();
+ $generator = $this->getDataGenerator();
+
+ // Create a course.
+ $course = $generator->create_course();
+ $context = \context_course::instance($course->id);
+
+ // Create a quiz.
+ /** @var \mod_quiz_generator $quizgenerator */
+ $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
+ $quizgenerator->create_instance([
+ 'course' => $course->id,
+ 'questionsperpage' => 0,
+ 'grade' => 100.0,
+ 'sumgrades' => 2,
+ ]);
+
+ // Create a page.
+ /** @var \mod_page_generator $pagegenerator */
+ $pagegenerator = $this->getDataGenerator()->get_plugin_generator('mod_page');
+ $pagegenerator->create_instance(['course' => $course->id]);
+
+ $courseactivities = \course_modinfo::get_array_of_activities($course, true);
+ $this->assertCount(2, $courseactivities);
+
+ $addtomoduleactivities = helper::get_modules_for_course($course->id);
+ $this->assertCount(1, $addtomoduleactivities);
+ }
+
+}
diff --git a/version.php b/version.php
new file mode 100644
index 0000000..ac24ec3
--- /dev/null
+++ b/version.php
@@ -0,0 +1,32 @@
+.
+
+/**
+ * Plugin version and other meta-data are defined here.
+ *
+ * @package qbank_qtoactivity
+ * @copyright 2023 Safat Shahin
+ * @author Luke Purnel, Henry Campbell, Mark Hay, Harrison Liddell
+ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->component = 'qbank_qtoactivity';
+$plugin->release = '1.0.0';
+$plugin->version = 2023013100;
+$plugin->requires = 2022041900;
+$plugin->maturity = MATURITY_STABLE;