diff --git a/lang/en/question.php b/lang/en/question.php index d9df15e60ca..7dc290e5ef7 100644 --- a/lang/en/question.php +++ b/lang/en/question.php @@ -142,6 +142,17 @@ $string['errorprocessingresponses'] = 'An error occurred while processing your r $string['errorsavingcomment'] = 'Error saving the comment for question {$a->name} in the database.'; $string['errorupdatingattempt'] = 'Error updating attempt {$a->id} in the database.'; $string['eventquestioncategorycreated'] = 'Question category created'; +$string['eventquestioncategorydeleted'] = 'Question category deleted'; +$string['eventquestioncategorymoved'] = 'Question category moved'; +$string['eventquestioncategoryupdated'] = 'Question category updated'; +$string['eventquestioncategoryviewed'] = 'Question category viewed'; +$string['eventquestioncreated'] = 'Question created'; +$string['eventquestiondeleted'] = 'Question deleted'; +$string['eventquestionmoved'] = 'Question moved'; +$string['eventquestionviewed'] = 'Question viewed'; +$string['eventquestionsexported'] = 'Questions exported'; +$string['eventquestionsimported'] = 'Questions imported'; +$string['eventquestionupdated'] = 'Question updated'; $string['export'] = 'Export'; $string['exportcategory'] = 'Export category'; $string['exportcategory_help'] = 'This setting determines the category from which the exported questions will be taken. diff --git a/lib/classes/event/question_base.php b/lib/classes/event/question_base.php new file mode 100644 index 00000000000..2f07b8587cb --- /dev/null +++ b/lib/classes/event/question_base.php @@ -0,0 +1,129 @@ +. + +/** + * Base class for question events. + * + * @package core + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Base class for question events. + * + * @package core + * @since Moodle 3.7 + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +abstract class question_base extends base { + + /** + * Init method. + */ + protected function init() { + $this->data['objecttable'] = 'question'; + $this->data['edulevel'] = self::LEVEL_TEACHING; + } + + /** + * Returns relevant URL. + * + * @return \moodle_url + */ + public function get_url() { + if ($this->courseid) { + $cat = $this->other['categoryid'] . ',' . $this->contextid; + 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/category.php', + ['courseid' => SITEID, 'edit' => $this->other['categoryid'], 'lastchanged' => $this->objectid]); + } + + /** + * Custom validations. + * + * @throws \coding_exception + * @return void + */ + protected function validate_data() { + parent::validate_data(); + + if (!isset($this->other['categoryid'])) { + throw new \coding_exception('The \'categoryid\' must be set in \'other\'.'); + } + } + + /** + * Returns DB mappings used with backup / restore. + * + * @return array + */ + public static function get_objectid_mapping() { + return ['db' => 'question', 'restore' => 'question']; + } + + /** + * Used for maping events on restore + * + * @return array + */ + public static function get_other_mapping() { + + $othermapped = []; + $othermapped['categoryid'] = ['db' => 'question_categories', 'restore' => 'question_categories']; + return $othermapped; + } + + /** + * Create a event from question object + * + * @param object $question + * @param object|null $context + * @param array|null $other will override the categoryid pre-filled out on the first line. + * @return base + * @throws \coding_exception + */ + public static function create_from_question_instance($question, $context = null, $other = null) { + + $params = ['objectid' => $question->id, 'other' => ['categoryid' => $question->category]]; + + if (!empty($question->contextid)) { + $params['contextid'] = $question->contextid; + } + + $params['context'] = $context; + + if (!empty($other)) { + $params['other'] = $other; + } + + $event = self::create($params); + return $event; + } +} + diff --git a/lib/classes/event/question_category_base.php b/lib/classes/event/question_category_base.php new file mode 100644 index 00000000000..fa1ffc79c3a --- /dev/null +++ b/lib/classes/event/question_category_base.php @@ -0,0 +1,95 @@ +. + +/** + * Base class for question category events. + * + * @package core + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Base class for question category events + * + * @package core + * @since Moodle 3.7 + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +abstract class question_category_base extends base { + + /** + * Init method. + */ + protected function init() { + $this->data['objecttable'] = 'question_categories'; + $this->data['edulevel'] = self::LEVEL_TEACHING; + } + + /** + * Returns relevant URL. + * + * @return \moodle_url + */ + public function get_url() { + if ($this->courseid) { + $cat = $this->objectid . ',' . $this->contextid; + 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/category.php', ['courseid' => SITEID, 'edit' => $this->objectid]); + } + + /** + * Returns DB mappings used with backup / restore. + * + * @return array + */ + public static function get_objectid_mapping() { + return ['db' => 'question_categories', 'restore' => 'question_categories']; + } + + /** + * Create a event from question category object + * + * @param object $category + * @param object|null $context + * @return base + * @throws \coding_exception + */ + public static function create_from_question_category_instance($category, $context = null) { + + $params = ['objectid' => $category->id]; + + if (!empty($category->contextid)) { + $params['contextid'] = $category->contextid; + } + + $params['context'] = $context; + + $event = self::create($params); + return $event; + } +} + diff --git a/lib/classes/event/question_category_created.php b/lib/classes/event/question_category_created.php index dd011eccb83..2b6baf14e05 100644 --- a/lib/classes/event/question_category_created.php +++ b/lib/classes/event/question_category_created.php @@ -34,15 +34,14 @@ defined('MOODLE_INTERNAL') || die(); * @copyright 2014 Mark Nelson * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class question_category_created extends base { +class question_category_created extends question_category_base { /** * Init method. */ protected function init() { - $this->data['objecttable'] = 'question_categories'; + parent::init(); $this->data['crud'] = 'c'; - $this->data['edulevel'] = self::LEVEL_TEACHING; } /** @@ -63,26 +62,6 @@ class question_category_created extends base { return "The user with id '$this->userid' created the question category with id '$this->objectid'."; } - /** - * Returns relevant URL. - * - * @return \moodle_url - */ - public function get_url() { - if ($this->courseid) { - $cat = $this->objectid . ',' . $this->contextid; - if ($this->contextlevel == CONTEXT_MODULE) { - return new \moodle_url('/question/edit.php', array('cmid' => $this->contextinstanceid, 'cat' => $cat)); - } - return new \moodle_url('/question/edit.php', array('courseid' => $this->courseid, 'cat' => $cat)); - } - - // Bad luck, there does not seem to be any simple intelligent way - // to go to specific question category in context above course, - // let's try to edit it from frontpage which may surprisingly work. - return new \moodle_url('/question/category.php', array('courseid' => SITEID, 'edit' => $this->objectid)); - } - /** * Return the legacy event log data. * @@ -97,7 +76,4 @@ class question_category_created extends base { return null; } - public static function get_objectid_mapping() { - return array('db' => 'question_categories', 'restore' => 'question_category'); - } } diff --git a/lib/classes/event/question_category_deleted.php b/lib/classes/event/question_category_deleted.php new file mode 100644 index 00000000000..94c5e76a38c --- /dev/null +++ b/lib/classes/event/question_category_deleted.php @@ -0,0 +1,65 @@ +. + +/** + * Question category deleted event. + * + * @package core + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Question category deleted event class. + * + * @package core + * @since Moodle 3.7 + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class question_category_deleted extends question_category_base { + + /** + * Init method. + */ + protected function init() { + parent::init(); + $this->data['crud'] = 'd'; + } + + /** + * Returns localised general event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventquestioncategorydeleted', 'question'); + } + + /** + * Returns description of what happened. + * + * @return string + */ + public function get_description() { + return "The user with id '$this->userid' deleted the question category with id '$this->objectid'."; + } + +} diff --git a/lib/classes/event/question_category_moved.php b/lib/classes/event/question_category_moved.php new file mode 100644 index 00000000000..05e867b9e1b --- /dev/null +++ b/lib/classes/event/question_category_moved.php @@ -0,0 +1,65 @@ +. + +/** + * Question category moved event. + * + * @package core + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Question category moved event class. + * + * @package core + * @since Moodle 3.7 + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class question_category_moved extends question_category_base { + + /** + * Init method. + */ + protected function init() { + parent::init(); + $this->data['crud'] = 'u'; + } + + /** + * Returns localised general event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventquestioncategorymoved', 'question'); + } + + /** + * Returns description of what happened. + * + * @return string + */ + public function get_description() { + return "The user with id '$this->userid' moved the question category with id '$this->objectid'."; + } + +} diff --git a/lib/classes/event/question_category_updated.php b/lib/classes/event/question_category_updated.php new file mode 100644 index 00000000000..e5b0e244919 --- /dev/null +++ b/lib/classes/event/question_category_updated.php @@ -0,0 +1,64 @@ +. + +/** + * Question category updated event. + * + * @package core + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Question category updated event class. + * + * @package core + * @since Moodle 3.7 + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class question_category_updated extends question_category_base { + + /** + * Init method. + */ + protected function init() { + parent::init(); + $this->data['crud'] = 'u'; + } + + /** + * Returns localised general event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventquestioncategoryupdated', 'question'); + } + + /** + * Returns description of what happened. + * + * @return string + */ + public function get_description() { + return "The user with id '$this->userid' updated the question category with id '$this->objectid'."; + } +} diff --git a/lib/classes/event/question_category_viewed.php b/lib/classes/event/question_category_viewed.php new file mode 100644 index 00000000000..d6595eb5ddb --- /dev/null +++ b/lib/classes/event/question_category_viewed.php @@ -0,0 +1,65 @@ +. + +/** + * Question category viewed event. + * + * @package core + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Question category viewed event class. + * + * @package core + * @since Moodle 3.7 + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class question_category_viewed extends question_category_base { + + /** + * Init method. + */ + protected function init() { + parent::init(); + $this->data['crud'] = 'r'; + } + + /** + * Returns localised general event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventquestioncategoryviewed', 'question'); + } + + /** + * Returns description of what happened. + * + * @return string + */ + public function get_description() { + return "The user with id '$this->userid' viewed the question category with id '$this->objectid'."; + } + +} diff --git a/lib/classes/event/question_created.php b/lib/classes/event/question_created.php new file mode 100644 index 00000000000..b05e1fb151d --- /dev/null +++ b/lib/classes/event/question_created.php @@ -0,0 +1,87 @@ +. + +/** + * Question created event. + * + * @package core + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Question created event class. + * + * @property-read array $other { + * Extra information about the event. + * + * - int categoryid: The ID of the category where the question resides + * } + * + * @package core + * @since Moodle 3.7 + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class question_created extends question_base { + + /** + * Init method. + */ + protected function init() { + parent::init(); + $this->data['crud'] = 'c'; + } + + /** + * Returns localised general event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventquestioncreated', 'question'); + } + + /** + * Returns description of what happened. + * + * @return string + */ + public function get_description() { + return "The user with id '$this->userid' created a question with the id of '$this->objectid'" . + " in the category with the id '" . $this->other['categoryid'] . "'."; + } + + /** + * Returns relevant URL. + * + * @return \moodle_url + */ + public function get_url() { + if ($this->courseid) { + if ($this->contextlevel == CONTEXT_MODULE) { + return new \moodle_url('/question/preview.php', ['cmid' => $this->contextinstanceid, 'id' => $this->objectid]); + } + return new \moodle_url('/question/preview.php', ['courseid' => $this->courseid, 'id' => $this->objectid]); + } + // Lets try editing from the frontpage for contexts above course. + return new \moodle_url('/question/preview.php', ['courseid' => SITEID, 'id' => $this->objectid]); + } +} diff --git a/lib/classes/event/question_deleted.php b/lib/classes/event/question_deleted.php new file mode 100644 index 00000000000..17363d10147 --- /dev/null +++ b/lib/classes/event/question_deleted.php @@ -0,0 +1,82 @@ +. + +/** + * Question deleted event. + * + * @package core + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Question deleted event class. + * + * @property-read array $other { + * Extra information about the event. + * + * - int categoryid: The ID of the category where the question resides + * } + * + * @package core + * @since Moodle 3.7 + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class question_deleted extends question_base { + + /** + * Init method. + */ + protected function init() { + parent::init(); + $this->data['crud'] = 'd'; + } + + /** + * Returns localised general event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventquestiondeleted', 'question'); + } + + /** + * Returns description of what happened. + * + * @return string + */ + public function get_description() { + return "The user with id '$this->userid' deleted the question with id '$this->objectid'" . + " from the category with the id '" . $this->other['categoryid'] . "'."; + } + + /** + * Returns relevant URL. + * This is needed to override the function in question_base + * + * @return \moodle_url + */ + public function get_url() { + // No URL for delete. + return null; + } +} diff --git a/lib/classes/event/question_moved.php b/lib/classes/event/question_moved.php new file mode 100644 index 00000000000..a798f813df2 --- /dev/null +++ b/lib/classes/event/question_moved.php @@ -0,0 +1,132 @@ +. + +/** + * Question moved event. + * + * @package core + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Question moved event class. + * + * @property-read array $other { + * Extra information about the event. + * + * - int newcategoryid: The ID of the new category of the question + * - int oldcategoryid: The ID of the old category of the question + * } + * + * @package core + * @since Moodle 3.7 + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class question_moved extends question_base { + + /** + * Init method. + */ + protected function init() { + parent::init(); + $this->data['crud'] = 'u'; + } + + /** + * Returns localised general event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventquestionmoved', 'question'); + } + + /** + * Returns description of what happened. + * + * @return string + */ + public function get_description() { + return "The user with id '$this->userid' moved the question with the id of '$this->objectid'" . + " from the category with the id of '" . $this->other['oldcategoryid'] . + "' to the category with the id of '" . $this->other['newcategoryid'] . "'."; + } + + /** + * Returns relevant URL. + * + * @return \moodle_url + */ + public function get_url() { + if ($this->courseid) { + $cat = $this->other['newcategoryid'] . ',' . $this->contextid; + 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/category.php', + ['courseid' => SITEID, 'edit' => $this->other['newcategoryid'], 'lastchanged' => $this->objectid]); + } + + /** + * Custom validations. + * + * @throws \coding_exception + * @return void + */ + protected function validate_data() { + + if (!isset($this->other['oldcategoryid'])) { + throw new \coding_exception('The \'oldcategoryid\' must be set in \'other\'.'); + } + if (!isset($this->other['newcategoryid'])) { + throw new \coding_exception('The \'newcategoryid\' must be set in \'other\'.'); + } + } + + /** + * Returns DB mappings used with backup / restore. + * + * @return array + */ + public static function get_objectid_mapping() { + return ['db' => 'question', 'restore' => 'question']; + } + + /** + * Used for maping events on restore + * + * @return array + */ + public static function get_other_mapping() { + + $othermapped = []; + $othermapped['newcategoryid'] = ['db' => 'question_categories', 'restore' => 'question_categories']; + $othermapped['oldcategoryid'] = ['db' => 'question_categories', 'restore' => 'question_categories']; + + return $othermapped; + } +} diff --git a/lib/classes/event/question_updated.php b/lib/classes/event/question_updated.php new file mode 100644 index 00000000000..4e5bdf93fa8 --- /dev/null +++ b/lib/classes/event/question_updated.php @@ -0,0 +1,71 @@ +. + +/** + * Question updated event. + * + * @package core + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Question updated event class. + * + * @property-read array $other { + * Extra information about the event. + * + * - int categoryid: The ID of the category where the question resides + * } + * + * @package core + * @since Moodle 3.7 + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class question_updated extends question_base { + + /** + * Init method. + */ + protected function init() { + parent::init(); + $this->data['crud'] = 'u'; + } + + /** + * Returns localised general event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventquestionupdated', 'question'); + } + + /** + * Returns description of what happened. + * + * @return string + */ + public function get_description() { + return "The user with id '$this->userid' updated the question with the id of '$this->objectid'."; + } + +} diff --git a/lib/classes/event/question_viewed.php b/lib/classes/event/question_viewed.php new file mode 100644 index 00000000000..9ef0d37ee39 --- /dev/null +++ b/lib/classes/event/question_viewed.php @@ -0,0 +1,71 @@ +. + +/** + * Question previewed event. + * + * @package core + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Question previewed event class. + * + * @property-read array $other { + * Extra information about the event. + * + * - int categoryid: The ID of the category where the question resides + * } + * + * @package core + * @since Moodle 3.7 + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class question_viewed extends question_base { + + /** + * Init method. + */ + protected function init() { + parent::init(); + $this->data['crud'] = 'r'; + } + + /** + * Returns localised general event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventquestionviewed', 'question'); + } + + /** + * Returns description of what happened. + * + * @return string + */ + public function get_description() { + return "The user with id '$this->userid' viewed the question with the id of '$this->objectid'."; + } + +} diff --git a/lib/classes/event/questions_exported.php b/lib/classes/event/questions_exported.php new file mode 100644 index 00000000000..adc3117a481 --- /dev/null +++ b/lib/classes/event/questions_exported.php @@ -0,0 +1,116 @@ +. + +/** + * Questions exported event. + * + * @package core + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Question category exported event class. + * + * @property-read array $other { + * Extra information about the event. + * + * - int categoryid: The ID of the category where the question resides + * - string format: The format of file export + * } + * + * @package core + * @since Moodle 3.7 + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class questions_exported extends question_base { + + /** + * Init method. + */ + protected function init() { + $this->data['crud'] = 'r'; + $this->data['edulevel'] = self::LEVEL_TEACHING; + } + + /** + * Returns localised general event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventquestionsexported', 'question'); + } + + /** + * Returns description of what happened. + * + * @return string + */ + public function get_description() { + return "The user with id '$this->userid' exported questions in '" . $this->other['format'] . + "' format from the category with id '" . $this->other['categoryid'] . "'."; + } + + /** + * Returns relevant URL. + * + * @return \moodle_url + */ + public function get_url() { + if ($this->courseid) { + $cat = $this->other['categoryid'] . ',' . $this->contextid; + 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/category.php', ['courseid' => SITEID, 'edit' => $this->other['categoryid']]); + } + + /** + * Custom validations. + * + * other['categoryid'] and other['format'] is required. + * + * @throws \coding_exception + * @return void + */ + protected function validate_data() { + parent::validate_data(); + + if (!isset($this->other['format'])) { + throw new \coding_exception('The \'format\' must be set in \'other\'.'); + } + } + + /** + * Returns DB mappings used with backup / restore. + * This is needed to override the function in question_base + * + * @return array + */ + public static function get_objectid_mapping() { + // No mappings. + return []; + } + +} diff --git a/lib/classes/event/questions_imported.php b/lib/classes/event/questions_imported.php new file mode 100644 index 00000000000..d774c40b9d8 --- /dev/null +++ b/lib/classes/event/questions_imported.php @@ -0,0 +1,115 @@ +. + +/** + * Questions imported event. + * + * @package core + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Question category imported event class. + * + * @property-read array $other { + * Extra information about the event. + * + * - int categoryid: The ID of the category where the question resides + * - string format: The format of file import + * } + * + * @package core + * @since Moodle 3.7 + * @copyright 2019 Stephen Bourget + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class questions_imported extends question_base { + + /** + * Init method. + */ + protected function init() { + $this->data['crud'] = 'c'; + $this->data['edulevel'] = self::LEVEL_TEACHING; + } + + /** + * Returns localised general event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventquestionsimported', 'question'); + } + + /** + * Returns description of what happened. + * + * @return string + */ + public function get_description() { + return "The user with id '$this->userid' imported questions in '" . $this->other['format'] . + "' format into the category with id '" . $this->other['categoryid'] . "'."; + } + + /** + * Returns relevant URL. + * + * @return \moodle_url + */ + public function get_url() { + if ($this->courseid) { + $cat = $this->other['categoryid'] . ',' . $this->contextid; + 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/category.php', ['courseid' => SITEID, 'edit' => $this->other['categoryid']]); + } + + /** + * Custom validations. + * + * other['categoryid'] and other['format'] is required. + * + * @throws \coding_exception + * @return void + */ + protected function validate_data() { + parent::validate_data(); + + if (!isset($this->other['format'])) { + throw new \coding_exception('The \'format\' must be set in \'other\'.'); + } + } + + /** + * Returns DB mappings used with backup / restore. + * This is needed to override the function in question_base + * + * @return array + */ + public static function get_objectid_mapping() { + // No mappings. + return []; + } +} diff --git a/lib/questionlib.php b/lib/questionlib.php index a465c7debec..6d96f8452a3 100644 --- a/lib/questionlib.php +++ b/lib/questionlib.php @@ -380,6 +380,11 @@ function question_delete_question($questionid) { // Finally delete the question record itself $DB->delete_records('question', array('id' => $questionid)); question_bank::notify_question_edited($questionid); + + // Log the deletion of this question. + $event = \core\event\question_deleted::create_from_question_instance($question); + $event->add_record_snapshot('question', $question); + $event->trigger(); } /** @@ -673,7 +678,7 @@ function question_move_questions_to_category($questionids, $newcategoryid) { array('id' => $newcategoryid)); list($questionidcondition, $params) = $DB->get_in_or_equal($questionids); $questions = $DB->get_records_sql(" - SELECT q.id, q.qtype, qc.contextid, q.idnumber + SELECT q.id, q.qtype, qc.contextid, q.idnumber, q.category FROM {question} q JOIN {question_categories} qc ON q.category = qc.id WHERE q.id $questionidcondition", $params); @@ -703,6 +708,11 @@ function question_move_questions_to_category($questionids, $newcategoryid) { $q->idnumber = $question->idnumber . '_' . $unique; $DB->update_record('question', $q); } + + // Log this question move. + $event = \core\event\question_moved::create_from_question_instance($question, context::instance_by_id($question->contextid), + ['oldcategoryid' => $question->category, 'newcategoryid' => $newcategoryid]); + $event->trigger(); } // Move the questions themselves. diff --git a/question/category.php b/question/category.php index 8e4ae0e7af7..c740522a63a 100644 --- a/question/category.php +++ b/question/category.php @@ -81,6 +81,12 @@ if ($param->moveupcontext || $param->movedowncontext) { print_error('invalidcontext'); } $oldcat = $DB->get_record('question_categories', array('id' => $catid), '*', MUST_EXIST); + // Log the move to another context. + $category = new stdClass(); + $category->id = explode(',', $pagevars['cat'], -1)[0]; + $category->contextid = $param->tocontext; + $event = \core\event\question_category_moved::create_from_question_category_instance($category); + $event->trigger(); $qcobject->update_category($catid, "{$newtopcat->id},{$param->tocontext}", $oldcat->name, $oldcat->info); // The previous line does a redirect(). } diff --git a/question/category_class.php b/question/category_class.php index a3394624d00..856da40420c 100644 --- a/question/category_class.php +++ b/question/category_class.php @@ -76,8 +76,35 @@ class question_category_list extends moodle_list { $topcategory = question_get_top_category($item->item->contextid, true); return $topcategory->id; } -} + /** + * process any actions. + * + * @param integer $left id of item to move left + * @param integer $right id of item to move right + * @param integer $moveup id of item to move up + * @param integer $movedown id of item to move down + * @return void + * @throws coding_exception + */ + public function process_actions($left, $right, $moveup, $movedown) { + $category = new stdClass(); + if (!empty($left)) { + // Moved Left (In to another category). + $category->id = $left; + $category->contextid = $this->context->id; + $event = \core\event\question_category_moved::create_from_question_category_instance($category); + $event->trigger(); + } else if (!empty($right)) { + // Moved Right (Out of the current category). + $category->id = $right; + $category->contextid = $this->context->id; + $event = \core\event\question_category_moved::create_from_question_category_instance($category); + $event->trigger(); + } + parent::process_actions($left, $right, $moveup, $movedown); + } +} /** * An item in a list of question categories. @@ -375,6 +402,12 @@ class question_category_object { /// Finally delete the category itself $DB->delete_records("question_categories", array("id" => $category->id)); + + // Log the deletion of this category. + $event = \core\event\question_category_deleted::create_from_question_category_instance($category); + $event->add_record_snapshot('question_categories', $category); + $event->trigger(); + } public function move_questions_and_delete_category($oldcat, $newcat){ @@ -442,11 +475,10 @@ class question_category_object { $categoryid = $DB->insert_record("question_categories", $cat); // Log the creation of this category. - $params = array( - 'objectid' => $categoryid, - 'contextid' => $contextid - ); - $event = \core\event\question_category_created::create($params); + $category = new stdClass(); + $category->id = $categoryid; + $category->contextid = $contextid; + $event = \core\event\question_category_created::create_from_question_category_instance($category); $event->trigger(); if ($return) { @@ -458,9 +490,18 @@ class question_category_object { /** * Updates an existing category with given params + * + * @param int $updateid + * @param int $newparent + * @param string $newname + * @param string $newinfo + * @param int $newinfoformat + * @param int $idnumber + * @param bool $redirect + * @return int */ public function update_category($updateid, $newparent, $newname, $newinfo, $newinfoformat = FORMAT_HTML, - $idnumber = null) { + $idnumber = null, $redirect = true) { global $CFG, $DB; if (empty($newname)) { print_error('categorynamecantbeblank', 'question'); @@ -519,6 +560,10 @@ class question_category_object { } $DB->update_record('question_categories', $cat); + // Log the update of this category. + $event = \core\event\question_category_updated::create_from_question_category_instance($cat); + $event->trigger(); + // If the category name has changed, rename any random questions in that category. if ($oldcat->name != $cat->name) { $where = "qtype = 'random' AND category = ? AND " . $DB->sql_compare_text('questiontext') . " = ?"; @@ -538,6 +583,8 @@ class question_category_object { // Cat param depends on the context id, so update it. $this->pageurl->param('cat', $updateid . ',' . $tocontextid); - redirect($this->pageurl); + if ($redirect) { + redirect($this->pageurl); // Always redirect after successful action. + } } } diff --git a/question/edit.php b/question/edit.php index 9d3295ec558..8c6e069c2a9 100644 --- a/question/edit.php +++ b/question/edit.php @@ -39,8 +39,6 @@ $PAGE->set_url($url); $questionbank = new core_question\bank\view($contexts, $thispageurl, $COURSE, $cm); $questionbank->process_actions(); -// TODO log this page view. - $context = $contexts->lowest(); $streditingquestions = get_string('editquestions', 'question'); $PAGE->set_title($streditingquestions); @@ -57,4 +55,12 @@ $questionbank->display('questions', $pagevars['qpage'], $pagevars['qperpage'], $pagevars['qbshowtext'], $pagevars['qtagids']); echo "\n"; +// Log the view of this category. +list($categoryid, $contextid) = explode(',', $pagevars['cat']); +$category = new stdClass(); +$category->id = $categoryid; +$catcontext = \context::instance_by_id($contextid); +$event = \core\event\question_category_viewed::create_from_question_category_instance($category, $catcontext); +$event->trigger(); + echo $OUTPUT->footer(); diff --git a/question/export.php b/question/export.php index 434526dad9c..07d48dc0af1 100644 --- a/question/export.php +++ b/question/export.php @@ -77,6 +77,14 @@ if ($from_form = $export_form->get_data()) { echo get_string('yourfileshoulddownload', 'question', $export_url->out()); echo $OUTPUT->box_end(); + // Log the export of these questions. + $eventparams = [ + 'contextid' => $category->contextid, + 'other' => ['format' => $from_form->format, 'categoryid' => $category->id], + ]; + $event = \core\event\questions_exported::create($eventparams); + $event->trigger(); + // Don't allow force download for behat site, as pop-up can't be handled by selenium. if (!defined('BEHAT_SITE_RUNNING')) { $PAGE->requires->js_function_call('document.location.replace', array($export_url->out(false)), false, 1); diff --git a/question/format.php b/question/format.php index 60fd4fa4cee..6cf40e5b0df 100644 --- a/question/format.php +++ b/question/format.php @@ -426,6 +426,8 @@ class qformat_default { ); $question->id = $DB->insert_record('question', $question); + $event = \core\event\question_created::create_from_question_instance($question, $this->importcontext); + $event->trigger(); if (isset($question->questiontextitemid)) { $question->questiontext = file_save_draft_area_files($question->questiontextitemid, @@ -613,6 +615,8 @@ class qformat_default { $category->stamp = make_unique_id_code(); $category->id = $DB->insert_record('question_categories', $category); $parent = $category->id; + $event = \core\event\question_category_created::create_from_question_category_instance($category, $context); + $event->trigger(); } } return $category; diff --git a/question/import.php b/question/import.php index c9dc091db8e..0f68d1ee684 100644 --- a/question/import.php +++ b/question/import.php @@ -129,6 +129,14 @@ if ($form = $import_form->get_data()) { print_error('cannotimport', '', $thispageurl->out()); } + // Log the import into this category. + $eventparams = [ + 'contextid' => $qformat->category->contextid, + 'other' => ['format' => $form->format, 'categoryid' => $qformat->category->id], + ]; + $event = \core\event\questions_imported::create($eventparams); + $event->trigger(); + $params = $thispageurl->params() + array( 'category' => $qformat->category->id . ',' . $qformat->category->contextid); echo $OUTPUT->continue_button(new moodle_url('edit.php', $params)); diff --git a/question/preview.php b/question/preview.php index 2f0908b8bed..cff9994674b 100644 --- a/question/preview.php +++ b/question/preview.php @@ -280,6 +280,10 @@ if (question_has_capability_on($question, 'view')) { get_string('exportonequestion', 'question')); } +// Log the preview of this question. +$event = \core\event\question_viewed::create_from_question_instance($question, $context); +$event->trigger(); + // Display the settings form. $optionsform->display(); diff --git a/question/tests/events_test.php b/question/tests/events_test.php index 357422e4e15..0f93b8605f9 100644 --- a/question/tests/events_test.php +++ b/question/tests/events_test.php @@ -73,4 +73,386 @@ class core_question_events_testcase extends advanced_testcase { $this->assertEventLegacyLogData($expected, $event); $this->assertEventContextNotUsed($event); } + + /** + * Test the question category deleted event. + */ + public function test_question_category_deleted() { + $this->setAdminUser(); + $course = $this->getDataGenerator()->create_course(); + $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]); + + $contexts = new question_edit_contexts(context_module::instance($quiz->cmid)); + + $defaultcategoryobj = question_make_default_categories([$contexts->lowest()]); + $defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid; + + $qcobject = new question_category_object( + 1, + new moodle_url('/mod/quiz/edit.php', ['cmid' => $quiz->cmid]), + $contexts->having_one_edit_tab_cap('categories'), + $defaultcategoryobj->id, + $defaultcategory, + null, + $contexts->having_cap('moodle/question:add')); + + // Create the category. + $categoryid = $qcobject->add_category($defaultcategory, 'newcategory', '', true); + + // Trigger and capture the event. + $sink = $this->redirectEvents(); + $qcobject->delete_category($categoryid); + $events = $sink->get_events(); + $event = reset($events); + + // Check that the event data is valid. + $this->assertInstanceOf('\core\event\question_category_deleted', $event); + $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context()); + $this->assertEquals($categoryid, $event->objectid); + $this->assertDebuggingNotCalled(); + } + + /** + * Test the question category updated event. + */ + public function test_question_category_updated() { + $this->setAdminUser(); + $course = $this->getDataGenerator()->create_course(); + $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]); + + $contexts = new question_edit_contexts(context_module::instance($quiz->cmid)); + + $defaultcategoryobj = question_make_default_categories([$contexts->lowest()]); + $defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid; + + $qcobject = new question_category_object( + 1, + new moodle_url('/mod/quiz/edit.php', ['cmid' => $quiz->cmid]), + $contexts->having_one_edit_tab_cap('categories'), + $defaultcategoryobj->id, + $defaultcategory, + null, + $contexts->having_cap('moodle/question:add')); + + // Create the category. + $categoryid = $qcobject->add_category($defaultcategory, 'newcategory', '', true); + + // Trigger and capture the event. + $sink = $this->redirectEvents(); + $qcobject->update_category($categoryid, $defaultcategory, 'updatedcategory', '', FORMAT_HTML, '', false); + $events = $sink->get_events(); + $event = reset($events); + + // Check that the event data is valid. + $this->assertInstanceOf('\core\event\question_category_updated', $event); + $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context()); + $this->assertEquals($categoryid, $event->objectid); + $this->assertDebuggingNotCalled(); + } + + /** + * Test the question category viewed event. + * There is no external API for viewing the category, so the unit test will simply + * create and trigger the event and ensure data is returned as expected. + */ + public function test_question_category_viewed() { + + $this->setAdminUser(); + $course = $this->getDataGenerator()->create_course(); + $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]); + + $contexts = new question_edit_contexts(context_module::instance($quiz->cmid)); + + $defaultcategoryobj = question_make_default_categories([$contexts->lowest()]); + $defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid; + + $qcobject = new question_category_object( + 1, + new moodle_url('/mod/quiz/edit.php', ['cmid' => $quiz->cmid]), + $contexts->having_one_edit_tab_cap('categories'), + $defaultcategoryobj->id, + $defaultcategory, + null, + $contexts->having_cap('moodle/question:add')); + + // Create the category. + $categoryid = $qcobject->add_category($defaultcategory, 'newcategory', '', true); + + // Log the view of this category. + $category = new stdClass(); + $category->id = $categoryid; + $context = context_module::instance($quiz->cmid); + $event = \core\event\question_category_viewed::create_from_question_category_instance($category, $context); + + // Trigger and capture the event. + $sink = $this->redirectEvents(); + $event->trigger(); + $events = $sink->get_events(); + $event = reset($events); + + // Check that the event data is valid. + $this->assertInstanceOf('\core\event\question_category_viewed', $event); + $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context()); + $this->assertEquals($categoryid, $event->objectid); + $this->assertDebuggingNotCalled(); + + } + + /** + * Test the questions imported event. + * There is no easy way to trigger this event using the API, so the unit test will simply + * create and trigger the event and ensure data is returned as expected. + */ + public function test_questions_imported() { + + $this->setAdminUser(); + $course = $this->getDataGenerator()->create_course(); + $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]); + + $contexts = new question_edit_contexts(context_module::instance($quiz->cmid)); + + $defaultcategoryobj = question_make_default_categories([$contexts->lowest()]); + $defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid; + + $qcobject = new question_category_object( + 1, + new moodle_url('/mod/quiz/edit.php', ['cmid' => $quiz->cmid]), + $contexts->having_one_edit_tab_cap('categories'), + $defaultcategoryobj->id, + $defaultcategory, + null, + $contexts->having_cap('moodle/question:add')); + + // Create the category. + $categoryid = $qcobject->add_category($defaultcategory, 'newcategory', '', true); + + // Log the view of this category. + $params = [ + 'context' => context_module::instance($quiz->cmid), + 'other' => ['categoryid' => $categoryid, 'format' => 'testformat'], + ]; + + $event = \core\event\questions_imported::create($params); + + // Trigger and capture the event. + $sink = $this->redirectEvents(); + $event->trigger(); + $events = $sink->get_events(); + $event = reset($events); + + // Check that the event data is valid. + $this->assertInstanceOf('\core\event\questions_imported', $event); + $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context()); + $this->assertEquals($categoryid, $event->other['categoryid']); + $this->assertEquals('testformat', $event->other['format']); + $this->assertDebuggingNotCalled(); + + } + + /** + * Test the questions exported event. + * There is no easy way to trigger this event using the API, so the unit test will simply + * create and trigger the event and ensure data is returned as expected. + */ + public function test_questions_exported() { + + $this->setAdminUser(); + $course = $this->getDataGenerator()->create_course(); + $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]); + + $contexts = new question_edit_contexts(context_module::instance($quiz->cmid)); + + $defaultcategoryobj = question_make_default_categories([$contexts->lowest()]); + $defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid; + + $qcobject = new question_category_object( + 1, + new moodle_url('/mod/quiz/edit.php', ['cmid' => $quiz->cmid]), + $contexts->having_one_edit_tab_cap('categories'), + $defaultcategoryobj->id, + $defaultcategory, + null, + $contexts->having_cap('moodle/question:add')); + + // Create the category. + $categoryid = $qcobject->add_category($defaultcategory, 'newcategory', '', true); + + // Log the view of this category. + $params = [ + 'context' => context_module::instance($quiz->cmid), + 'other' => ['categoryid' => $categoryid, 'format' => 'testformat'], + ]; + + $event = \core\event\questions_exported::create($params); + + // Trigger and capture the event. + $sink = $this->redirectEvents(); + $event->trigger(); + $events = $sink->get_events(); + $event = reset($events); + + // Check that the event data is valid. + $this->assertInstanceOf('\core\event\questions_exported', $event); + $this->assertEquals(context_module::instance($quiz->cmid), $event->get_context()); + $this->assertEquals($categoryid, $event->other['categoryid']); + $this->assertEquals('testformat', $event->other['format']); + $this->assertDebuggingNotCalled(); + + } + + /** + * Test the question created event. + */ + public function test_question_created() { + + $this->setAdminUser(); + $generator = $this->getDataGenerator()->get_plugin_generator('core_question'); + + $cat = $generator->create_question_category(['name' => 'My category', 'sortorder' => 1]); + + // Trigger and capture the event. + $sink = $this->redirectEvents(); + $questiondata = $generator->create_question('description', null, ['category' => $cat->id]); + $question = question_bank::load_question($questiondata->id); + + $events = $sink->get_events(); + $event = reset($events); + + // Check that the event data is valid. + $this->assertInstanceOf('\core\event\question_created', $event); + $this->assertEquals($question->id, $event->objectid); + $this->assertEquals($cat->id, $event->other['categoryid']); + $this->assertDebuggingNotCalled(); + + } + + /** + * Test the question deleted event. + */ + public function test_question_deleted() { + + $this->setAdminUser(); + $generator = $this->getDataGenerator()->get_plugin_generator('core_question'); + + $cat = $generator->create_question_category(['name' => 'My category', 'sortorder' => 1]); + + $questiondata = $generator->create_question('description', null, ['category' => $cat->id]); + $question = question_bank::load_question($questiondata->id); + + // Trigger and capture the event. + $sink = $this->redirectEvents(); + question_delete_question($question->id); + $events = $sink->get_events(); + $event = reset($events); + + // Check that the event data is valid. + $this->assertInstanceOf('\core\event\question_deleted', $event); + $this->assertEquals($question->id, $event->objectid); + $this->assertEquals($cat->id, $event->other['categoryid']); + $this->assertDebuggingNotCalled(); + + } + + /** + * Test the question updated event. + */ + public function test_question_updated() { + + global $CFG; + require_once($CFG->dirroot . '/question/type/description/questiontype.php'); + require_once($CFG->dirroot . '/question/type/edit_question_form.php'); + require_once($CFG->dirroot . '/question/type/description/edit_description_form.php'); + + $this->setAdminUser(); + $generator = $this->getDataGenerator()->get_plugin_generator('core_question'); + + $cat = $generator->create_question_category(['name' => 'My category', 'sortorder' => 1]); + + $questiondata = $generator->create_question('description', null, ['category' => $cat->id]); + $question = question_bank::load_question($questiondata->id); + + $qtype = new qtype_description(); + $formdata = test_question_maker::get_question_form_data('description'); + $formdata->category = "{$cat->id},{$cat->contextid}"; + qtype_description_edit_form::mock_submit((array) $formdata); + + $form = qtype_description_test_helper::get_question_editing_form($cat, $questiondata); + $fromform = $form->get_data(); + + // Trigger and capture the event. + $sink = $this->redirectEvents(); + $qtype->save_question($questiondata, $fromform); + $events = $sink->get_events(); + $event = reset($events); + + // Check that the event data is valid. + $this->assertInstanceOf('\core\event\question_updated', $event); + $this->assertEquals($question->id, $event->objectid); + $this->assertEquals($cat->id, $event->other['categoryid']); + $this->assertDebuggingNotCalled(); + + } + + /** + * Test the question moved event. + */ + public function test_question_moved() { + + $this->setAdminUser(); + $generator = $this->getDataGenerator()->get_plugin_generator('core_question'); + + $cat1 = $generator->create_question_category([ + 'name' => 'My category 1', 'sortorder' => 1]); + + $cat2 = $generator->create_question_category([ + 'name' => 'My category 2', 'sortorder' => 2]); + + $questiondata = $generator->create_question('description', null, ['category' => $cat1->id]); + $question = question_bank::load_question($questiondata->id); + + // Trigger and capture the event. + $sink = $this->redirectEvents(); + question_move_questions_to_category([$question->id], $cat2->id); + $events = $sink->get_events(); + $event = reset($events); + + // Check that the event data is valid. + $this->assertInstanceOf('\core\event\question_moved', $event); + $this->assertEquals($question->id, $event->objectid); + $this->assertEquals($cat1->id, $event->other['oldcategoryid']); + $this->assertEquals($cat2->id, $event->other['newcategoryid']); + $this->assertDebuggingNotCalled(); + + } + + /** + * Test the question viewed event. + * There is no external API for viewing the question, so the unit test will simply + * create and trigger the event and ensure data is returned as expected. + */ + public function test_question_viewed() { + + $this->setAdminUser(); + $generator = $this->getDataGenerator()->get_plugin_generator('core_question'); + + $cat = $generator->create_question_category(['name' => 'My category', 'sortorder' => 1]); + + $questiondata = $generator->create_question('description', null, ['category' => $cat->id]); + $question = question_bank::load_question($questiondata->id); + + $event = \core\event\question_viewed::create_from_question_instance($question, context::instance_by_id($cat->contextid)); + + // Trigger and capture the event. + $sink = $this->redirectEvents(); + $event->trigger(); + $events = $sink->get_events(); + $event = reset($events); + + // Check that the event data is valid. + $this->assertInstanceOf('\core\event\question_viewed', $event); + $this->assertEquals($question->id, $event->objectid); + $this->assertEquals($cat->id, $event->other['categoryid']); + $this->assertDebuggingNotCalled(); + + } } diff --git a/question/type/questiontypebase.php b/question/type/questiontypebase.php index 294975d1ee9..7af20957460 100644 --- a/question/type/questiontypebase.php +++ b/question/type/questiontypebase.php @@ -364,12 +364,14 @@ class question_type { } // If the question is new, create it. + $newquestion = false; if (empty($question->id)) { // Set the unique code. $question->stamp = make_unique_id_code(); $question->createdby = $USER->id; $question->timecreated = time(); $question->id = $DB->insert_record('question', $question); + $newquestion = true; } // Now, whether we are updating a existing question, or creating a new @@ -391,6 +393,16 @@ class question_type { } $DB->update_record('question', $question); + if ($newquestion) { + // Log the creation of this question. + $event = \core\event\question_created::create_from_question_instance($question, $context); + $event->trigger(); + } else { + // Log the update of this question. + $event = \core\event\question_updated::create_from_question_instance($question, $context); + $event->trigger(); + } + // Now to save all the answers and type-specific options. $form->id = $question->id; $form->qtype = $question->qtype; diff --git a/version.php b/version.php index 0809475211d..af28588ea95 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2019042700.00; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2019042700.01; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes.