diff --git a/lang/en/access.php b/lang/en/access.php index 6fe361641fe..ae8e241fb74 100644 --- a/lang/en/access.php +++ b/lang/en/access.php @@ -29,6 +29,8 @@ $string['accessstatement'] = 'Accessibility statement'; $string['activitynext'] = 'Next activity'; $string['activityprev'] = 'Previous activity'; $string['breadcrumb'] = 'Navigation bar'; +$string['eventcontextlocked'] = 'Context frozen'; +$string['eventcontextunlocked'] = 'Context unfrozen'; $string['hideblocka'] = 'Hide {$a} block'; $string['showblocka'] = 'Show {$a} block'; $string['sitemap'] = 'Site map'; diff --git a/lib/accesslib.php b/lib/accesslib.php index e80ba19c445..b3f9a41356c 100644 --- a/lib/accesslib.php +++ b/lib/accesslib.php @@ -5254,6 +5254,15 @@ abstract class context extends stdClass implements IteratorAggregate { $this->_locked = $locked; $DB->set_field('context', 'locked', (int) $locked, ['id' => $this->id]); $this->mark_dirty(); + + if ($locked) { + $eventname = '\\core\\event\\context_locked'; + } else { + $eventname = '\\core\\event\\context_unlocked'; + } + $event = $eventname::create(['context' => $this, 'objectid' => $this->id]); + $event->trigger(); + self::reset_caches(); return $this; diff --git a/lib/classes/event/context_locked.php b/lib/classes/event/context_locked.php new file mode 100644 index 00000000000..f4bf9904c0b --- /dev/null +++ b/lib/classes/event/context_locked.php @@ -0,0 +1,85 @@ +. + +/** + * Context locked event. + * + * @package core_access + * @copyright 2019 University of Nottingham + * @author Neill Magill + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Event triggered after a context has been frozen. + * + * @package core_access + * @since Moodle 3.8 + * @copyright 2019 University of Nottingham + * @author Neill Magill + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class context_locked extends base { + /** + * Returns description of what happened. + * + * @return string + */ + public function get_description() { + return "The user with id '$this->userid' locked the context with id '$this->objectid' "; + } + + /** + * Return localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventcontextlocked', 'access'); + } + + /** + * Get URL related to the action + * + * @return \moodle_url + */ + public function get_url() { + // Try to get the url for the context. + try { + $context = \context::instance_by_id($this->objectid); + $url = $context->get_url(); + } catch (\dml_missing_record_exception $e) { + // The context no longer exists, give them the system url instead. + $url = \context_system::instance()->get_url(); + } + return $url; + } + + /** + * Init method. + * + * @return void + */ + protected function init() { + $this->data['crud'] = 'u'; + $this->data['edulevel'] = self::LEVEL_OTHER; + $this->data['objecttable'] = 'context'; + } +} diff --git a/lib/classes/event/context_unlocked.php b/lib/classes/event/context_unlocked.php new file mode 100644 index 00000000000..92e6ece1c5c --- /dev/null +++ b/lib/classes/event/context_unlocked.php @@ -0,0 +1,85 @@ +. + +/** + * Context unlocked event. + * + * @package core_access + * @copyright 2019 University of Nottingham + * @author Neill Magill + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Event triggered after a context has been unfrozen. + * + * @package core_access + * @since Moodle 3.8 + * @copyright 2019 University of Nottingham + * @author Neill Magill + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class context_unlocked extends base { + /** + * Returns description of what happened. + * + * @return string + */ + public function get_description() { + return "The user with id '$this->userid' unlocked the context with id '$this->objectid' "; + } + + /** + * Return localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventcontextunlocked', 'access'); + } + + /** + * Get URL related to the action + * + * @return \moodle_url + */ + public function get_url() { + // Try to get the url for the context. + try { + $context = \context::instance_by_id($this->objectid); + $url = $context->get_url(); + } catch (\dml_missing_record_exception $e) { + // The context no longer exists, give them the system url instead. + $url = \context_system::instance()->get_url(); + } + return $url; + } + + /** + * Init method. + * + * @return void + */ + protected function init() { + $this->data['crud'] = 'u'; + $this->data['edulevel'] = self::LEVEL_OTHER; + $this->data['objecttable'] = 'context'; + } +} diff --git a/lib/tests/event_context_locked_test.php b/lib/tests/event_context_locked_test.php new file mode 100644 index 00000000000..2a7a43532c8 --- /dev/null +++ b/lib/tests/event_context_locked_test.php @@ -0,0 +1,109 @@ +. + +/** + * Unit tests for the context locking events. + * + * @package core + * @category test + * @copyright 2019 University of Nottingham + * @author Neill Magill + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +use core\event\context_locked; +use core\event\context_unlocked; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Unit tests for the context_locked and context_unlocked events. + * + * @package core + * @category test + * @copyright 2019 University of Nottingham + * @author Neill Magill + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class core_event_context_locked_testcase extends \advanced_testcase { + /** + * Locks an unlocked context and checks that a core\event\context_locked event is created. + * + * @param \context $context + */ + protected function lock_context(\context $context) { + self::assertFalse($context->is_locked()); + + $locksink = $this->redirectEvents(); + $context->set_locked(true); + // This second call should not create an event as the lock status has not changed. + $context->set_locked(true); + $lockevents = $locksink->get_events(); + $locksink->close(); + + self::assertCount(1, $lockevents); + self::assertContainsOnlyInstancesOf('core\event\context_locked', $lockevents); + self::assertEquals($context->id, $lockevents[0]->objectid); + $this->assertSame('context', $lockevents[0]->objecttable); + $this->assertEquals($context, $lockevents[0]->get_context()); + } + + /** + * Tests that events are created when contexts are locked and unlocked. + */ + public function test_creation() { + $this->resetAfterTest(); + + $category = self::getDataGenerator()->create_category(); + $catcontext = \context_coursecat::instance($category->id); + $course = self::getDataGenerator()->create_course(['category' => $category->id]); + $coursecontext = \context_course::instance($course->id); + $activitygenerator = self::getDataGenerator()->get_plugin_generator('mod_forum'); + $activity = $activitygenerator->create_instance(['course' => $course->id]); + $activitycontext = \context_module::instance($activity->cmid); + + $this->lock_context($catcontext); + $this->unlock_context($catcontext); + + $this->lock_context($coursecontext); + $this->unlock_context($coursecontext); + + $this->lock_context($activitycontext); + $this->unlock_context($activitycontext); + } + + /** + * Unlocks a locked context and checks that a core\event\context_unlocked event is created. + * + * @param \context $context + */ + protected function unlock_context(\context $context) { + self::assertTrue($context->is_locked()); + + $unlocksink = $this->redirectEvents(); + $context->set_locked(false); + // This second call should not create an event as the lock status has not changed. + $context->set_locked(false); + $unlockevents = $unlocksink->get_events(); + $unlocksink->close(); + + self::assertCount(1, $unlockevents); + self::assertContainsOnlyInstancesOf('core\event\context_unlocked', $unlockevents); + self::assertEquals($context->id, $unlockevents[0]->objectid); + $this->assertSame('context', $unlockevents[0]->objecttable); + $this->assertEquals($context, $unlockevents[0]->get_context()); + } +}