From 92b40de9de64458bec58709fdb404b2bf792c18c Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Thu, 19 Jun 2014 15:16:45 +0800 Subject: [PATCH 01/44] MDL-45758 tool_monitor: Add basic file structure of the report Original issue - MDL-45916 --- admin/tool/monitor/db/access.php | 53 +++++++++++++++++++++ admin/tool/monitor/lang/en/tool_monitor.php | 29 +++++++++++ admin/tool/monitor/version.php | 31 ++++++++++++ lib/classes/plugin_manager.php | 2 +- 4 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 admin/tool/monitor/db/access.php create mode 100644 admin/tool/monitor/lang/en/tool_monitor.php create mode 100644 admin/tool/monitor/version.php diff --git a/admin/tool/monitor/db/access.php b/admin/tool/monitor/db/access.php new file mode 100644 index 00000000000..d1b687ce76d --- /dev/null +++ b/admin/tool/monitor/db/access.php @@ -0,0 +1,53 @@ +. + +/** + * Capabilities. + * + * This files lists capabilities related to tool_monitor. + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$capabilities = array( + + 'tool/monitor:subscribe' => array( + 'riskbitmask' => RISK_PERSONAL, + 'captype' => 'read', + 'contextlevel' => CONTEXT_COURSE, + 'archetypes' => array( + 'teacher' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW + ), + ), + + 'tool/monitor:managerules' => array( + 'riskbitmask' => RISK_XSS, + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'archetypes' => array( + 'teacher' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW + ), + ), +); + diff --git a/admin/tool/monitor/lang/en/tool_monitor.php b/admin/tool/monitor/lang/en/tool_monitor.php new file mode 100644 index 00000000000..f00316c11ac --- /dev/null +++ b/admin/tool/monitor/lang/en/tool_monitor.php @@ -0,0 +1,29 @@ +. + +/** + * Lang strings. + * + * This files lists lang strings related to tool_monitor. + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['pluginname'] = 'Event monitor'; +$string['tool/monitor:managerules'] = 'Manage event monitor rules'; +$string['tool/monitor:subscribe'] = 'Subscribe to event monitor rules'; diff --git a/admin/tool/monitor/version.php b/admin/tool/monitor/version.php new file mode 100644 index 00000000000..dba36966a9b --- /dev/null +++ b/admin/tool/monitor/version.php @@ -0,0 +1,31 @@ +. + +/** + * Version info + * + * This file contains version information about tool_monitor. + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die; + +$plugin->version = 2014061900; // The current plugin version (Date: YYYYMMDDXX). +$plugin->requires = 2014061900; // Requires this Moodle version. +$plugin->component = 'tool_monitor'; // Full name of the plugin (used for diagnostics). diff --git a/lib/classes/plugin_manager.php b/lib/classes/plugin_manager.php index 334de7c6b9d..6e8ee69d850 100644 --- a/lib/classes/plugin_manager.php +++ b/lib/classes/plugin_manager.php @@ -1137,7 +1137,7 @@ class core_plugin_manager { 'tool' => array( 'assignmentupgrade', 'availabilityconditions', 'behat', 'capability', 'customlang', 'dbtransfer', 'generator', 'health', 'innodb', 'installaddon', - 'langimport', 'log', 'messageinbound', 'multilangupgrade', 'phpunit', 'profiling', + 'langimport', 'log', 'messageinbound', 'multilangupgrade', 'monitor', 'phpunit', 'profiling', 'replace', 'spamcleaner', 'task', 'timezoneimport', 'unittest', 'uploadcourse', 'uploaduser', 'unsuproles', 'xmldb' ), From d0d6c72de24419a8af576c37efe3ecf0c920e836 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Thu, 19 Jun 2014 16:41:35 +0800 Subject: [PATCH 02/44] MDL-45758 tool_monitor: Adding xml file defining the db tables Original issue - MDL-45916 --- admin/tool/monitor/db/install.xml | 80 +++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 admin/tool/monitor/db/install.xml diff --git a/admin/tool/monitor/db/install.xml b/admin/tool/monitor/db/install.xml new file mode 100644 index 00000000000..39d2bb94ef7 --- /dev/null +++ b/admin/tool/monitor/db/install.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+
+
\ No newline at end of file From f235cae41f9e31ed4ed17040052c28f1ab44b97c Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Tue, 1 Jul 2014 17:15:55 +0800 Subject: [PATCH 03/44] MDL-45758 tool_monitor: Implement a class to generate list of events Original issue - MDL-46109 --- admin/tool/monitor/classes/eventlist.php | 220 +++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 admin/tool/monitor/classes/eventlist.php diff --git a/admin/tool/monitor/classes/eventlist.php b/admin/tool/monitor/classes/eventlist.php new file mode 100644 index 00000000000..b503fd8b9c7 --- /dev/null +++ b/admin/tool/monitor/classes/eventlist.php @@ -0,0 +1,220 @@ +. + +/** + * Event documentation + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace tool_monitor; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Class for returning event information. + * + * @since Moodle 2.8 + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class eventlist { + /** + * Return all of the core event files. + * + * @return array Core events. + */ + protected static function get_core_eventlist() { + global $CFG; + + // Disable developer debugging as deprecated events will fire warnings. + // Setup backup variables to restore the following settings back to what they were when we are finished. + $debuglevel = $CFG->debug; + $debugdisplay = $CFG->debugdisplay; + $debugdeveloper = $CFG->debugdeveloper; + $CFG->debug = 0; + $CFG->debugdisplay = false; + $CFG->debugdeveloper = false; + + $eventinformation = array(); + $directory = $CFG->libdir . '/classes/event'; + $files = self::get_file_list($directory); + + // Remove exceptional events that will cause problems being displayed. + if (isset($files['unknown_logged'])) { + unset($files['unknown_logged']); + } + foreach ($files as $file => $location) { + $classname = '\\core\\event\\' . $file; + // Check to see if this is actually a valid event. + if (method_exists($classname, 'get_static_info')) { + $ref = new \ReflectionClass($classname); + // Ignore abstracts. + if (!$ref->isAbstract() && $file != 'manager') { + $eventinformation[$classname] = $classname::get_name(); + } + } + } + // Now enable developer debugging as event information has been retrieved. + $CFG->debug = $debuglevel; + $CFG->debugdisplay = $debugdisplay; + $CFG->debugdeveloper = $debugdeveloper; + return $eventinformation; + } + + /** + * This function returns an array of all events for the plugins of the system. + * + * @param bool $withoutcomponent Return an eventlist without associated components. + * + * @return array A list of events from all plug-ins. + */ + protected static function get_non_core_eventlist($withoutcomponent = false) { + global $CFG; + // Disable developer debugging as deprecated events will fire warnings. + // Setup backup variables to restore the following settings back to what they were when we are finished. + $debuglevel = $CFG->debug; + $debugdisplay = $CFG->debugdisplay; + $debugdeveloper = $CFG->debugdeveloper; + $CFG->debug = 0; + $CFG->debugdisplay = false; + $CFG->debugdeveloper = false; + + $noncorepluginlist = array(); + $plugintypes = \core_component::get_plugin_types(); + foreach ($plugintypes as $plugintype => $notused) { + $pluginlist = \core_component::get_plugin_list($plugintype); + foreach ($pluginlist as $plugin => $directory) { + $plugindirectory = $directory . '/classes/event'; + foreach (self::get_file_list($plugindirectory) as $eventname => $notused) { + $plugineventname = '\\' . $plugintype . '_' . $plugin . '\\event\\' . $eventname; + // Check that this is actually an event. + if (method_exists($plugineventname, 'get_static_info') && $plugin != 'monitor') { // No selfie here. + $ref = new \ReflectionClass($plugineventname); + if (!$ref->isAbstract() && $plugin != 'legacy') { + if ($withoutcomponent) { + $noncorepluginlist[$plugineventname] = $plugineventname::get_name(); + } else { + $noncorepluginlist[$plugintype . '_' . $plugin][$plugineventname] = $plugineventname::get_name(); + } + } + } + } + } + } + + // Now enable developer debugging as event information has been retrieved. + $CFG->debug = $debuglevel; + $CFG->debugdisplay = $debugdisplay; + $CFG->debugdeveloper = $debugdeveloper; + + return $noncorepluginlist; + } + + /** + * Returns a list of files with a full directory path in a specified directory. + * + * @param string $directory location of files. + * @return array full location of files from the specified directory. + */ + protected static function get_file_list($directory) { + global $CFG; + $directoryroot = $CFG->dirroot; + $finalfiles = array(); + if (is_dir($directory)) { + if ($handle = opendir($directory)) { + $files = scandir($directory); + foreach ($files as $file) { + if ($file != '.' && $file != '..') { + // Ignore the file if it is external to the system. + if (strrpos($directory, $directoryroot) !== false) { + $location = substr($directory, strlen($directoryroot)); + $name = substr($file, 0, -4); + $finalfiles[$name] = $location . '/' . $file; + } + } + } + } + } + return $finalfiles; + } + + /** + * Get a list of events present in the system. + * + * @param bool $withoutcomponent Return an eventlist without associated components. + * + * @return array list of events present in the system. + */ + public static function get_all_eventlist($withoutcomponent = false) { + if ($withoutcomponent) { + $return = array_merge(self::get_core_eventlist(), self::get_non_core_eventlist($withoutcomponent)); + } else { + $return = array_merge(array('core' => self::get_core_eventlist()), + self::get_non_core_eventlist($withoutcomponent = false)); + } + return $return; + } + + /** + * Return list of plugins that have events. + * + * @param array $eventlist a list of events present in the system {@link eventlist::get_all_eventlist}. + * + * @return array list of plugins with human readable name. + */ + public static function get_plugin_list($eventlist = array()) { + if (empty($eventlist)) { + $eventlist = self::get_all_eventlist(); + } + $plugins = array_keys($eventlist); + $return = array(); + foreach ($plugins as $plugin) { + if ($plugin === 'core') { + $return[$plugin] = get_string('core', 'tool_monitor'); + } else if (get_string_manager()->string_exists('pluginname', $plugin)) { + $return[$plugin] = get_string('pluginname', $plugin); + } else { + $return[$plugin] = $plugin; + } + } + + return $return; + } + + /** + * validate if the given event belongs to the given plugin. + * + * @param string $plugin Frankenstyle name of the plugin. + * @param string $eventname Full qualified event name. + * @param array $eventlist List of events generated by {@link eventlist::get_all_eventlist} + * + * @return bool Returns true if the selected event belongs to the selected plugin, false otherwise. + */ + public static function validate_event_plugin($plugin, $eventname, $eventlist = array()) { + if (empty($eventlist)) { + $eventlist = self::get_all_eventlist(); + } + if (isset($eventlist[$plugin][$eventname])) { + return true; + } + + return false; + } +} From 5f68d9ee2b47090785d0015289c143e7b06e9dcb Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Mon, 30 Jun 2014 17:44:38 +0800 Subject: [PATCH 04/44] MDL-45758 tool_monitor: Implement a rule instance class Original issue - MDL-45939 --- admin/tool/monitor/classes/helper_trait.php | 104 +++++++++++ admin/tool/monitor/classes/rule.php | 183 ++++++++++++++++++++ admin/tool/monitor/lang/en/tool_monitor.php | 6 + 3 files changed, 293 insertions(+) create mode 100644 admin/tool/monitor/classes/helper_trait.php create mode 100644 admin/tool/monitor/classes/rule.php diff --git a/admin/tool/monitor/classes/helper_trait.php b/admin/tool/monitor/classes/helper_trait.php new file mode 100644 index 00000000000..e810a8601cf --- /dev/null +++ b/admin/tool/monitor/classes/helper_trait.php @@ -0,0 +1,104 @@ +. + +/** + * Common methods that are needed both in rule and subscription class. + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace tool_monitor; + +defined('MOODLE_INTERNAL') || die(); +require_once($CFG->dirroot . '/lib/moodlelib.php'); + +/** + * Common methods that are needed both in rule and subscription class. + * + * @since Moodle 2.8 + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +trait helper_trait { + + /** + * Method to get event name. + * + * @return string + * @throws \coding_exception + */ + public function get_event_name() { + $eventclass = $this->eventname; + if (class_exists($eventclass)) { + return $eventclass::get_name(); + } + return get_string('eventnotfound', 'tool_monitor'); + } + + /** + * Get filter description. + * + * @return string + */ + public function get_filters_description() { + $a = new \stdClass(); + $a->freq = $this->frequency; + $mins = $this->timewindow / MINSECS; // Convert seconds to minutes. + $a->mins = $mins; + return get_string('freqdesc', 'tool_monitor', $a); + } + + /** + * Get properly formatted name of the rule associated. + * + * @param \context $context context where this name would be displayed. + * + * @return string Formatted name of the rule. + */ + public function get_name(\context $context) { + return format_text($this->name, FORMAT_HTML, array('context' => $context)); + } + + /** + * Get properly formatted description of the rule associated. + * + * @param \context $context context where this description would be displayed. + * + * @return string Formatted description of the rule. + */ + public function get_description(\context $context) { + return format_text($this->description, $this->descriptionformat, array('context' => $context)); + } + + /** + * Get name of the plugin associated with this rule + * + * @return string Plugin name. + */ + public function get_plugin_name() { + if ($this->plugin === 'core') { + $string = get_string('core', 'tool_monitor'); + } else if (get_string_manager()->string_exists('pluginname', $this->plugin)) { + $string = get_string('pluginname', $this->plugin); + } else { + $string = $this->plugin; + } + return $string; + } +} diff --git a/admin/tool/monitor/classes/rule.php b/admin/tool/monitor/classes/rule.php new file mode 100644 index 00000000000..9d23cbdff91 --- /dev/null +++ b/admin/tool/monitor/classes/rule.php @@ -0,0 +1,183 @@ +. + +/** + * Class represents a single rule. + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace tool_monitor; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Class represents a single rule. + * + * @since Moodle 2.8 + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class rule { + use helper_trait; + + /** + * @var \stdClass The rule object form database. + */ + protected $rule; + + /** + * Constructor. + * + * @param \stdClass $rule A rule object from database. + */ + public function __construct($rule) { + $this->rule = $rule; + } + + /** + * Can the current user manage this rule? + * + * @return bool true if the current user can manage this rule, else false. + */ + public function can_manage_rule() { + $courseid = $this->courseid; + $context = empty($courseid) ? \context_system::instance() : \context_course::instance($this->courseid); + return has_capability('tool/monitor:managerules', $context); + } + + /** + * Api to duplicate a rule in a given courseid. + * + * @param int $finalcourseid Final course id. + */ + public function duplicate_rule($finalcourseid) { + $rule = fullclone($this->rule); + unset($rule->id); + $rule->courseid = $finalcourseid; + $time = time(); + $rule->timecreated = $time; + $rule->timemodified = $time; + rule_manager::add_rule($rule); + } + + /** + * Delete this rule. + * + * Note: It also removes all associated subscriptions. + */ + public function delete_rule() { + rule_manager::delete_rule($this->id); + } + + /** + * Generate a select drop down with list of possible modules for a given course and rule. + * + * @param int $courseid course id + * + * @return \single_select a single select object + * @throws \coding_exception + */ + public function get_module_select($courseid) { + global $CFG; + $options = array(); + if (strpos($this->plugin, 'mod_') === 0) { + $options[0] = get_string('allmodules', 'tool_monitor'); + } else { + $options[0] = get_string('allevents', 'tool_monitor'); + } + if (strpos($this->plugin, 'mod_') === 0) { + if ($courseid == 0) { + // They need to be in a course to select module instance. + return get_string('selectcourse', 'tool_monitor'); + } + // Let them select an instance. + $cms = get_fast_modinfo($courseid); + $instances = $cms->get_instances_of(str_replace('mod_', '', $this->plugin)); + foreach ($instances as $cminfo) { + // Don't list instances that are not visible or available to the user. + if ($cminfo->uservisible && $cminfo->available) { + $options[$cminfo->id] = $cminfo->get_formatted_name(); + } + } + } + $url = new \moodle_url($CFG->wwwroot. '/tool/monitor/index.php', array('id' => $courseid, 'ruleid' => $this->id, + 'action' => 'subscribe')); + return new \single_select($url, 'cmid', $options, '', $nothing = array('' => 'choosedots')); + } + + /** + * Subscribe an user to this rule. + * + * @param int $courseid Course id. + * @param int $cmid Course module id. + * @param int $userid User id. + * + * @throws \coding_exception + */ + public function subscribe_user($courseid, $cmid, $userid = 0) { + global $USER; + + if ($this->courseid != $courseid && $this->courseid != 0) { + // Trying to subscribe to a rule that belongs to a different course. Should never happen. + throw new \coding_exception('Can not subscribe to rules from a different course'); + } + if ($cmid !== 0) { + $cms = get_fast_modinfo($courseid); + $cminfo = $cms->get_cm($cmid); + if (!$cminfo->uservisible || !$cminfo->available) { + // Trying to subscribe to a hidden or restricted cm. Should never happen. + throw new \coding_exception('You cannot do that'); + } + } + $userid = empty($userid) ? $USER->id : $userid; + + subscription_manager::create_subscription($this->id, $courseid, $cmid, $userid); + } + + /** + * Magic get method. + * + * @param string $prop property to get. + * + * @return mixed + * @throws \coding_exception + */ + public function __get($prop) { + if (property_exists($this->rule, $prop)) { + return $this->rule->$prop; + } + throw new \coding_exception('Property "' . $prop . '" doesn\'t exist'); + } + + /** + * Return the rule data to be used while setting mform. + * + * @throws \coding_exception + */ + public function get_mform_set_data() { + if (!empty($this->rule)) { + $rule = fullclone($this->rule); + $rule->description = array('text' => $rule->description, 'format' => $rule->descriptionformat); + $rule->template = array('text' => $rule->template, 'format' => $rule->templateformat); + return $rule; + } + throw new \coding_exception('Invalid call to get_mform_set_data.'); + } +} diff --git a/admin/tool/monitor/lang/en/tool_monitor.php b/admin/tool/monitor/lang/en/tool_monitor.php index f00316c11ac..b2ab10db38d 100644 --- a/admin/tool/monitor/lang/en/tool_monitor.php +++ b/admin/tool/monitor/lang/en/tool_monitor.php @@ -24,6 +24,12 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +$string['allevents'] = 'All events'; +$string['allmodules'] = 'All modules'; +$string['core'] = 'Core'; +$string['eventnotfound'] = 'Event not found'; +$string['freqdesc'] = '{$a->freq} times in {$a->mins} minutes'; $string['pluginname'] = 'Event monitor'; +$string['selectcourse'] = 'Visit this report at course level to get a list of possible modules'; $string['tool/monitor:managerules'] = 'Manage event monitor rules'; $string['tool/monitor:subscribe'] = 'Subscribe to event monitor rules'; From eccf301acf3e1e80064bf2dbdf39cee14bd814f1 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Mon, 30 Jun 2014 13:08:38 +0800 Subject: [PATCH 05/44] MDL-45758 navigation: updates to navigation This patch does the following:- Start using proper key for course report node Allow admin tools to hook into course navigation Original issue - MDL-46131 --- lib/navigationlib.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/navigationlib.php b/lib/navigationlib.php index 5359b56ed9e..179f2471b21 100644 --- a/lib/navigationlib.php +++ b/lib/navigationlib.php @@ -3753,7 +3753,7 @@ class settings_navigation extends navigation_node { // View course reports. if (has_capability('moodle/site:viewreports', $coursecontext)) { // Basic capability for listing of reports. - $reportnav = $coursenode->add(get_string('reports'), null, self::TYPE_CONTAINER, null, null, + $reportnav = $coursenode->add(get_string('reports'), null, self::TYPE_CONTAINER, null, 'coursereports', new pix_icon('i/stats', '')); $coursereports = core_component::get_plugin_list('coursereport'); foreach ($coursereports as $report => $dir) { @@ -3773,6 +3773,12 @@ class settings_navigation extends navigation_node { } } + // Let admin tools hook into course navigation. + $tools = get_plugin_list_with_function('tool', 'extend_navigation_course', 'lib.php'); + foreach ($tools as $toolfunction) { + $toolfunction($coursenode, $course, $coursecontext); + } + // Add view grade report is permitted $reportavailable = false; if (has_capability('moodle/grade:viewall', $coursecontext)) { From 3883eee06bd3708f4c5d8964b4a15e04ee93f3a5 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Mon, 30 Jun 2014 13:09:18 +0800 Subject: [PATCH 06/44] MDL-45758 tool_monitor: Build the navigation tree for the tool Original issue - MDL-46131 --- admin/tool/monitor/lang/en/tool_monitor.php | 2 + admin/tool/monitor/lib.php | 67 +++++++++++++++++++++ admin/tool/monitor/settings.php | 44 ++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 admin/tool/monitor/lib.php create mode 100644 admin/tool/monitor/settings.php diff --git a/admin/tool/monitor/lang/en/tool_monitor.php b/admin/tool/monitor/lang/en/tool_monitor.php index b2ab10db38d..4c59a8c8013 100644 --- a/admin/tool/monitor/lang/en/tool_monitor.php +++ b/admin/tool/monitor/lang/en/tool_monitor.php @@ -29,6 +29,8 @@ $string['allmodules'] = 'All modules'; $string['core'] = 'Core'; $string['eventnotfound'] = 'Event not found'; $string['freqdesc'] = '{$a->freq} times in {$a->mins} minutes'; +$string['managesubscriptions'] = 'Manage subscriptions'; +$string['managerules'] = 'Manage rules'; $string['pluginname'] = 'Event monitor'; $string['selectcourse'] = 'Visit this report at course level to get a list of possible modules'; $string['tool/monitor:managerules'] = 'Manage event monitor rules'; diff --git a/admin/tool/monitor/lib.php b/admin/tool/monitor/lib.php new file mode 100644 index 00000000000..e562f82ad4b --- /dev/null +++ b/admin/tool/monitor/lib.php @@ -0,0 +1,67 @@ +. + +/** + * This page lists public api for tool_monitor plugin. + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die; + +/** + * This function extends the navigation with the tool items + * + * @param navigation_node $navigation The navigation node to extend + * @param stdClass $course The course to object for the tool + * @param context $context The context of the course + */ +function tool_monitor_extend_navigation_course($navigation, $course, $context) { + $node = navigation_node::create(get_string('pluginname', 'tool_monitor'), null, navigation_node::TYPE_CONTAINER, null, + 'eventmonitor', new pix_icon('i/tool', '')); + + if (has_capability('tool/monitor:managerules', $context)) { + $url = new moodle_url('/admin/tool/monitor/managerules.php', array('courseid' => $course->id)); + $settingsnode = navigation_node::create(get_string('managerules', 'tool_monitor'), $url, navigation_node::TYPE_SETTING, + null, null, new pix_icon('i/settings', '')); + } + + if (has_capability('tool/monitor:subscribe', $context)) { + $url = new moodle_url('/admin/tool/monitor/index.php', array('courseid' => $course->id)); + $subsnode = navigation_node::create(get_string('managesubscriptions', 'tool_monitor'), $url, + navigation_node::TYPE_SETTING, null, null, new pix_icon('i/settings', '')); + } + + $reportnode = $navigation->get('coursereports'); + + if ((isset($subsnode) || isset($settingsnode)) && !empty($reportnode)) { + // Add the node only if there are sub pages. + $node = $reportnode->add_node($node); + + // Our navigation lib can not handle nodes that have active child, so we need to always add parent first without + // children. Refer MDL-45872 . + + if (isset($settingsnode)) { + $node->add_node($settingsnode); + } + + if (isset($subsnode)) { + $node->add_node($subsnode); + } + } +} diff --git a/admin/tool/monitor/settings.php b/admin/tool/monitor/settings.php new file mode 100644 index 00000000000..9bfc3013dc4 --- /dev/null +++ b/admin/tool/monitor/settings.php @@ -0,0 +1,44 @@ +. + +/** + * Links and settings + * + * This file contains links and settings used by tool_monitor + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +defined('MOODLE_INTERNAL') || die; + +if ($hassiteconfig) { + $ADMIN->add('reports', new admin_category('toolmonitor', new lang_string('pluginname', 'tool_monitor'))); + + // Manage rules page. + $url = new moodle_url('/admin/tool/monitor/managerules.php', array('courseid' => 0)); + $temp = new admin_externalpage('toolmonitorrules', get_string('managerules', 'tool_monitor'), $url, + 'tool/monitor:managerules'); + $ADMIN->add('toolmonitor', $temp); + + // Manage subscriptions page. + $url = new moodle_url('/admin/tool/monitor/index.php', array('courseid' => 0)); + $temp = new admin_externalpage('toolmonitorsubscriptions', get_string('managesubscriptions', 'tool_monitor'), $url, + 'tool/monitor:subscribe'); + $ADMIN->add('toolmonitor', $temp); + + $settings = null; +} From c8a081cc6bafb01516d6f252037c785222700a5e Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Wed, 25 Jun 2014 15:18:55 +0800 Subject: [PATCH 07/44] MDL-45758 tool_monitor: Add a subscription manager class Original issue - MDL-45919 --- .../monitor/classes/subscription_manager.php | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 admin/tool/monitor/classes/subscription_manager.php diff --git a/admin/tool/monitor/classes/subscription_manager.php b/admin/tool/monitor/classes/subscription_manager.php new file mode 100644 index 00000000000..f5665ffff8f --- /dev/null +++ b/admin/tool/monitor/classes/subscription_manager.php @@ -0,0 +1,173 @@ +. + +/** + * Class to manage subscriptions. + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace tool_monitor; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Class to manage subscriptions. + * + * @since Moodle 2.8 + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class subscription_manager { + /** + * Subscribe a user to a given rule. + * + * @param int $ruleid Rule id. + * @param int $courseid Course id. + * @param int $cmid Course module id. + * @param int $userid User who is subscribing, defaults to $USER. + * + * @return bool|int returns id of the created subscription. + */ + public static function create_subscription($ruleid, $courseid, $cmid, $userid = 0) { + global $DB, $USER; + + $subscription = new \stdClass(); + $subscription->ruleid = $ruleid; + $subscription->courseid = $courseid; + $subscription->cmid = $cmid; + $subscription->userid = empty($userid) ? $USER->id : $userid; + if ($DB->record_exists('tool_monitor_subscriptions', (array)$subscription)) { + // Subscription already exists. + return false; + } + + $subscription->timecreated = time(); + return $DB->insert_record('tool_monitor_subscriptions', $subscription); + } + + /** + * Delete a subscription. + * + * @param subscription|int $subscriptionorid an instance of subscription class or id. + * @param bool $checkuser Check if the subscription belongs to current user before deleting. + * + * @return bool + * @throws \coding_exception if $checkuser is true and the subscription doesn't belong to the current user. + */ + public static function delete_subscription($subscriptionorid, $checkuser = true) { + global $DB, $USER; + if (get_class($subscriptionorid) === 'tool_monitor\subscription') { + $subscription = $subscriptionorid; + } else { + $subscription = self::get_subscription($subscriptionorid); + } + if ($checkuser && $subscription->userid != $USER->id) { + throw new \coding_exception('Invalid subscription supplied'); + } + return $DB->delete_records('tool_monitor_subscriptions', array('id' => $subscription->id)); + } + + /** + * Delete all subscribers for a given rule. + * + * @param int $ruleid rule id. + * + * @return bool + */ + public static function remove_all_subscriptions_for_rule($ruleid) { + global $DB; + return $DB->delete_records('tool_monitor_subscriptions', array('ruleid' => $ruleid)); + } + + /** + * Get a subscription instance for an given subscription id. + * + * @param subscription|int $subscriptionorid an instance of subscription class or id. + * + * @return subscription returns a instance of subscription class. + */ + public static function get_subscription($subscriptionorid) { + global $DB; + + if (is_object($subscriptionorid)) { + return new subscription($subscriptionorid); + } + + $sql = self::get_subscription_join_rule_sql(); + $sql .= "WHERE s.id = :id"; + $sub = $DB->get_record_sql($sql, array('id' => $subscriptionorid), MUST_EXIST); + return new subscription($sub); + } + + /** + * Get an array of subscriptions for a given user in a given course. + * + * @param int $courseid course id. + * @param int $userid Id of the user for which the subscription needs to be fetched. Defaults to $USER; + * @param string $order Order to sort the subscriptions. + * + * @return array list of subscriptions + */ + public static function get_user_subscriptions_for_course($courseid, $userid = 0, $order = 's.timecreated DESC') { + global $DB, $USER; + if ($userid == 0) { + $userid = $USER->id; + } + $sql = self::get_subscription_join_rule_sql(); + $sql .= "WHERE s.courseid = :courseid AND s.userid = :userid $order"; + + return $DB->get_records_sql($sql, array('courseid' => $courseid, 'userid' => $userid)); + } + + /** + * Return a list of subscriptions for a given event. + * + * @param \stdClass $event the event object. + * + * @return array + */ + public static function get_subscriptions_by_event(\stdClass $event) { + global $DB; + + $sql = self::get_subscription_join_rule_sql(); + if ($event->contextlevel == CONTEXT_MODULE && $event->contextinstanceid != 0) { + $sql .= "WHERE r.eventname = :eventname AND s.courseid = :courseid AND (s.cmid = :cmid OR s.cmid = 0)"; + $params = array('eventname' => $event->eventname, 'courseid' => $event->courseid, 'cmid' => $event->contextinstanceid); + } else { + $sql .= "WHERE r.eventname = :eventname AND (s.courseid = :courseid OR s.courseid = 0)"; + $params = array('eventname' => $event->eventname, 'courseid' => $event->courseid); + } + return $DB->get_records_sql($sql, $params); + } + + /** + * Return sql to join rule and subscription table. + * + * @return string the sql. + */ + public static function get_subscription_join_rule_sql() { + $sql = "SELECT s.*, r.description, r.name, r.userid as ruleuserid, r.courseid as rulecourseid, r.plugin, + r.eventname, r.message_template, r.frequency, r.timewindow + FROM {tool_monitor_rules} r + JOIN {tool_monitor_subscriptions} s + ON r.id = s.ruleid "; + return $sql; + } +} From 7bdbb4dc2d0c9dd27131d099278cd142f0b08d52 Mon Sep 17 00:00:00 2001 From: Simey Lameze Date: Mon, 30 Jun 2014 12:08:45 +0800 Subject: [PATCH 08/44] MDL-45758 tool_monitor: Rule manager class and data generators This issue introduces rule manager class, data generators and unit tests associated with them. Original issue - MDL-45918 --- admin/tool/monitor/classes/rule_manager.php | 134 +++++++++++++ admin/tool/monitor/tests/generator/lib.php | 188 ++++++++++++++++++ admin/tool/monitor/tests/generator_test.php | 135 +++++++++++++ .../tool/monitor/tests/rule_manager_test.php | 134 +++++++++++++ 4 files changed, 591 insertions(+) create mode 100644 admin/tool/monitor/classes/rule_manager.php create mode 100644 admin/tool/monitor/tests/generator/lib.php create mode 100644 admin/tool/monitor/tests/generator_test.php create mode 100644 admin/tool/monitor/tests/rule_manager_test.php diff --git a/admin/tool/monitor/classes/rule_manager.php b/admin/tool/monitor/classes/rule_manager.php new file mode 100644 index 00000000000..71386238a6a --- /dev/null +++ b/admin/tool/monitor/classes/rule_manager.php @@ -0,0 +1,134 @@ +. + +/** + * Rule manager class. + * + * @package tool_monitor + * @copyright 2014 onwards Simey Lameze + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace tool_monitor; + +defined('MOODLE_INTERNAL') || die(); + +class rule_manager { + + /** + * Create a new rule. + * + * @param \stdClass $ruledata data to insert as new rule entry. + * @return \tool_monitor\rule object with rule id. + */ + public static function add_rule($ruledata) { + global $DB, $USER; + $now = time(); + $rule = new \stdClass(); + $rule->userid = empty($ruledata->userid) ? $USER->id : $ruledata->userid; + $rule->courseid = $ruledata->courseid; + $rule->name = $ruledata->name; + $rule->plugin = $ruledata->plugin; + $rule->eventname = $ruledata->eventname; + $rule->description = $ruledata->description; + $rule->frequency = (int)$ruledata->frequency; + $rule->message_template = $ruledata->message_template; + $rule->timewindow = $now; + $rule->timecreated = $now; + $rule->timemodified = $now; + $ruleid = $DB->insert_record('tool_monitor_rules', $rule, true); + + return new rule($ruleid); + } + + /** + * Delete a rule and subscriptions by rule id. + * + * @param int $ruleid id of rule to be deleted. + * @return bool + */ + public static function delete_rule($ruleid) { + global $DB; + + subscription_manager::remove_all_subscriptions_for_rule($ruleid); + return $DB->delete_records('tool_monitor_rules', array('id' => $ruleid)); + } + + /** + * Get a rule object by id. + * + * @param \stdClass|int $ruleorid A rule object from database or rule id. + * @return \tool_monitor\rule object with rule id. + */ + public static function get_rule($ruleorid) { + global $DB; + if (!is_object($ruleorid)) { + $rule = $DB->get_record('tool_monitor_rules', array('id' => $ruleorid), '*', MUST_EXIST); + } else { + $rule = $ruleorid; + } + + return new rule($rule); + } + + /** + * Update rule data. + * + * @throws coding_exception if $record->ruleid is invalid. + * @param object $params rule data to be updated. + * @return bool + */ + public static function update_rule($params) { + global $DB; + if (!self::get_rule($params->id)) { + throw new coding_exception('Invalid rule ID.'); + } + $params->timemodified = time(); + return $DB->update_record('tool_monitor_rules', $params, false); + } + + /** + * Get rules by course id. + * + * @param int $courseid course id of the rule. + * @return array rule data. + */ + public static function get_rules_by_courseid($courseid) { + global $DB; + return $DB->get_records('tool_monitor_rules', array('courseid' => $courseid)); + } + + /** + * Get rules by plugin name. + * + * @param string $plugin plugin name of the rule. + * @return array rule data. + */ + public static function get_rules_by_plugin($plugin) { + global $DB; + return $DB->get_records('tool_monitor_rules', array('plugin' => $plugin)); + } + + /** + * Get rules by event name. + * + * @param string $eventname event name of the rule. + * @return array rule data. + */ + public static function get_rules_by_event($eventname) { + global $DB; + return $DB->get_records('tool_monitor_rules', array('eventname' => $eventname)); + } +} \ No newline at end of file diff --git a/admin/tool/monitor/tests/generator/lib.php b/admin/tool/monitor/tests/generator/lib.php new file mode 100644 index 00000000000..174d6938505 --- /dev/null +++ b/admin/tool/monitor/tests/generator/lib.php @@ -0,0 +1,188 @@ +. + +/** + * Event monitor data generator + * + * @package tool_monitor + * @category test + * @copyright 2014 onwards Simey Lameze + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * Event monitor data generator class + * + * @since Moodle 2.8 + * @package tool_monitor + * @category test + * @copyright 2014 onwards Simey Lameze + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class tool_monitor_generator extends testing_module_generator { + + /** + * @var int keep track of how many rules have been created. + */ + protected $rulecount; + + /** + * Function to generate rule data. + * + * @param \stdClass|array $record data to insert as rule entry. + * @return \tool_monitor\rule object. + */ + public function create_rule($record = null) { + global $USER; + + $this->rulecount++; + $i = $this->rulecount; + $now = time(); + $record = (object)(array)$record; + + if (!isset($record->userid)) { + $record->userid = $USER->id; + } + if (!isset($record->courseid)) { + $record->courseid = 0; + } + if (!isset($record->name)) { + $record->name = 'Test rule ' . $i; + } + if (!isset($record->description)) { + $record->description = 'Rule description ' . $i; + } + if (!isset($record->frequency)) { + $record->frequency = 5; + } + if (!isset($record->minutes)) { + $record->minutes = 5; + } + if (!isset($record->message_template)) { + $record->message_template = 'Rule message template ' . $i; + } + if (!isset($record->timewindow)) { + $record->timewindow = $record->minutes * 60; + } + if (!isset($record->timecreated)) { + $record->timecreated = $now; + } + if (!isset($record->timemodified)) { + $record->timemodified = $now; + } + if (!isset($record->plugin)) { + $record->plugin = 'core'; + } + if (!isset($record->eventname)) { + $record->eventname = '\core\event\blog_entry_created'; + } + + return \tool_monitor\rule_manager::add_rule($record); + } + + /** + * Function to generate subscription data. + * + * @throws coding_exception if $record->ruleid or $record->userid not present. + * @param \stdClass|array $record data to insert as subscription entry. + * @return int subscription ID. + */ + public function create_subscription($record = null) { + + if (!isset($record->timecreated)) { + $record->timecreated = time(); + } + if (!isset($record->courseid)) { + $record->courseid = 0; + } + if (!isset($record->ruleid)) { + throw new coding_exception('$record->ruleid must be present in tool_monitor_generator::create_subscription()'); + } + if (!isset($record->cmid)) { + $record->cmid = 0; + } + if (!isset($record->userid)) { + throw new coding_exception('$record->userid must be present in tool_monitor_generator::create_subscription()'); + } + + return \tool_monitor\subscription_manager::create_subscription($record->ruleid, $record->courseid, + $record->cmid, $record->userid); + } + + /** + * Function to generate event entries. + * + * @param \stdClass|array $record data to insert as event entry. + * @return \stdClass $record object with event id. + */ + public function create_event_entries($record = null) { + global $DB, $CFG; + + $record = (object)(array)$record; + $context = \context_system::instance(); + + if (!isset($record->eventname)) { + $record->eventname = '\core\event\user_loggedin'; + } + if (!isset($record->contextid)) { + $record->contextid = $context->id; + } + if (!isset($record->contextlevel)) { + $record->contextlevel = $context->contextlevel; + } + if (!isset($record->contextinstanceid)) { + $record->contextinstanceid = $context->instanceid; + } + if (!isset($record->link)) { + $record->link = $CFG->wwwroot . '/user/profile.php'; + } + if (!isset($record->courseid)) { + $record->courseid = 0; + } + if (!isset($record->timecreated)) { + $record->timecreated = time(); + } + $record->id = $DB->insert_record('tool_monitor_events', $record, true); + + return $record; + } + + /** + * Function to generate history data. + * + * @throws coding_exception if $record->sid or $record->userid not present. + * @param \stdClass $record data to insert as history entry. + * @return \stdClass $record object with history id. + */ + public function create_history($record = null) { + global $DB; + + if (!isset($record->sid)) { + throw new coding_exception('subscription ID must be present in tool_monitor_generator::create_history() $record'); + } + if (!isset($record->userid)) { + throw new coding_exception('user ID must be present in tool_monitor_generator::create_history() $record'); + } + if (!isset($record->timesent)) { + $record->timesent = time(); + } + $record->id = $DB->insert_record('tool_monitor_history', $record, true); + + return $record; + } +} diff --git a/admin/tool/monitor/tests/generator_test.php b/admin/tool/monitor/tests/generator_test.php new file mode 100644 index 00000000000..18ebb9a018d --- /dev/null +++ b/admin/tool/monitor/tests/generator_test.php @@ -0,0 +1,135 @@ +. + +/** + * PHPUnit data generator tests. + * + * @package tool_monitor + * @category phpunit + * @copyright 2014 onwards Simey Lameze + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + + +/** + * PHPUnit data generator test case. + * + * @since Moodle 2.8 + * @package tool_monitor + * @category phpunit + * @copyright 2014 onwards Simey Lameze + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class tool_monitor_generator_testcase extends advanced_testcase { + + /** + * Test create_rule data generator. + */ + public function test_create_rule() { + $this->setAdminUser(); + $this->resetAfterTest(true); + $course = $this->getDataGenerator()->create_course(); + $user = $this->getDataGenerator()->create_user(); + + $rulegenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor'); + + $record = new stdClass(); + $record->courseid = $course->id; + $record->userid = $user->id; + + $rule = $rulegenerator->create_rule($record); + $this->assertInstanceOf('tool_monitor\rule', $rule); + $this->assertEquals($rule->userid, $record->userid); + $this->assertEquals($rule->courseid, $record->courseid); + } + + /** + * Test create_subscription data generator. + */ + public function test_create_subscription() { + $this->setAdminUser(); + $this->resetAfterTest(true); + + $user = $this->getDataGenerator()->create_user(); + $course = $this->getDataGenerator()->create_course(); + $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor'); + $rule = $monitorgenerator->create_rule(); + + $record = new stdClass(); + $record->courseid = $course->id; + $record->userid = $user->id; + $record->ruleid = $rule->id; + + $sid = $monitorgenerator->create_subscription($record); + $subscription = \tool_monitor\subscription_manager::get_subscription($sid); + $this->assertEquals($record->courseid, $subscription->courseid); + $this->assertEquals($record->ruleid, $subscription->ruleid); + $this->assertEquals($record->userid, $subscription->userid); + $this->assertEquals(0, $subscription->cmid); + } + + /** + * Test create_event data generator. + */ + public function test_create_event_entries() { + $this->setAdminUser(); + $this->resetAfterTest(true); + $record = new \stdClass(); + $context = \context_system::instance(); + + // Default data generator values. + $record->eventname = '\core\event\user_loggedin'; + $record->contextid = $context->id; + $record->contextlevel = $context->contextlevel; + $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor'); + + // First create and assertdata using default values. + $eventdata = $monitorgenerator->create_event_entries(); + $this->assertEquals($record->eventname, $eventdata->eventname); + $this->assertEquals($record->contextid, $eventdata->contextid); + $this->assertEquals($record->contextlevel, $eventdata->contextlevel); + } + + /** + * Test create_history data generator. + */ + public function test_create_history() { + $this->setAdminUser(); + $this->resetAfterTest(true); + $user = $this->getDataGenerator()->create_user(); + $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor'); + $rule = $monitorgenerator->create_rule(); + + $record = new \stdClass(); + $record->userid = $user->id; + $record->ruleid = $rule->id; + $sid = $monitorgenerator->create_subscription($record); + \tool_monitor\subscription_manager::get_subscription($sid); + $record->sid = $sid; + $historydata = $monitorgenerator->create_history($record); + $this->assertEquals($record->userid, $historydata->userid); + $this->assertEquals($record->sid, $historydata->sid); + + // Test using default values. + $record->userid = 1; + $record->sid = 1; + $historydata = $monitorgenerator->create_history($record); + $this->assertEquals(1, $historydata->userid); + $this->assertEquals(1, $historydata->sid); + } +} \ No newline at end of file diff --git a/admin/tool/monitor/tests/rule_manager_test.php b/admin/tool/monitor/tests/rule_manager_test.php new file mode 100644 index 00000000000..b75d17e916b --- /dev/null +++ b/admin/tool/monitor/tests/rule_manager_test.php @@ -0,0 +1,134 @@ +. + +/** + * Unit tests for rule manager api. + * + * @package tool_monitor + * @category phpunit + * @copyright 2014 onwards Simey Lameze + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; + +class rule_manager_testcase extends advanced_testcase { + + /** + * Test add_rule method. + */ + public function test_add_rule() { + $this->setAdminUser(); + $this->resetAfterTest(true); + + $user = $this->getDataGenerator()->create_user(); + $course = $this->getDataGenerator()->create_course(); + $now = time(); + + $rule = new \stdClass(); + $rule->userid = $user->id; + $rule->courseid = $course->id; + $rule->name = 'test rule 1'; + $rule->plugin = 'core'; + $rule->eventname = '\core\event\course_updated'; + $rule->description = 'test description 1'; + $rule->frequency = 15; + $rule->message_template = 'test template message'; + $rule->timewindow = null; + $rule->timecreated = $now; + $rule->timemodified = $now; + + $ruledata = \tool_monitor\rule_manager::add_rule($rule); + + $this->assertEquals($rule->eventname, $ruledata->eventname); + $this->assertEquals($rule->userid, $ruledata->userid); + $this->assertEquals($rule->courseid, $ruledata->courseid); + + } + + /** + * Test get_rule method. + */ + public function test_get_rule() { + $this->setAdminUser(); + $this->resetAfterTest(true); + + $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor'); + $rule = $monitorgenerator->create_rule(); + $rules1 = \tool_monitor\rule_manager::get_rule($rule->id); + $this->assertInstanceOf('tool_monitor\rule', $rules1); + } + + /** + * Test update_rule method. + */ + public function test_update_rule() { + $this->setAdminUser(); + $this->resetAfterTest(true); + + $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor'); + $rule = $monitorgenerator->create_rule(); + + $ruledata = new stdClass; + $ruledata->id = $rule->id; + $ruledata->frequency = 25; + + \tool_monitor\rule_manager::update_rule($ruledata); + $this->assertNotEquals($ruledata->frequency, $rule->frequency); + + } + + /** + * Test get_rules_by_courseid method. + */ + public function test_get_rules_by_courseid() { + $this->setAdminUser(); + $this->resetAfterTest(true); + + $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor'); + $rule = $monitorgenerator->create_rule(); + $ruledata = \tool_monitor\rule_manager::get_rules_by_courseid($rule->courseid); + $this->assertEquals($rule->courseid, 0); + } + + /** + * Test get_rules_by_plugin method. + */ + public function test_get_rules_by_plugin() { + $this->setAdminUser(); + $this->resetAfterTest(true); + + $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor'); + $rule = $monitorgenerator->create_rule(); + $rules1 = \tool_monitor\rule_manager::get_rules_by_plugin($rule->plugin); + $this->assertEquals(1, count($rules1)); + } + + /** + * Test get_rules_by_event method. + */ + public function test_get_rules_by_event() { + $this->setAdminUser(); + $this->resetAfterTest(true); + + $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor'); + $rule = $monitorgenerator->create_rule(); + $rules1 = \tool_monitor\rule_manager::get_rules_by_event($rule->eventname); + $this->assertEquals(1, count($rules1)); + } +} \ No newline at end of file From 3d27d680a800d0a16195f1154e231a12fbb7000a Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Mon, 7 Jul 2014 14:07:55 +0800 Subject: [PATCH 09/44] MDL-45758 tool_monitor: Polish the code for rule manager and unit tests Original issue - MDL-45918 --- admin/tool/monitor/classes/rule_manager.php | 116 +++++++++++++----- admin/tool/monitor/tests/generator/lib.php | 30 +++-- admin/tool/monitor/tests/generator_test.php | 26 ++-- .../tool/monitor/tests/rule_manager_test.php | 88 ++++++++++--- 4 files changed, 185 insertions(+), 75 deletions(-) diff --git a/admin/tool/monitor/classes/rule_manager.php b/admin/tool/monitor/classes/rule_manager.php index 71386238a6a..97ca8c5913b 100644 --- a/admin/tool/monitor/classes/rule_manager.php +++ b/admin/tool/monitor/classes/rule_manager.php @@ -25,38 +25,67 @@ namespace tool_monitor; defined('MOODLE_INTERNAL') || die(); +/** + * Rule manager class. + * + * @package tool_monitor + * @copyright 2014 onwards Simey Lameze + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ class rule_manager { /** * Create a new rule. * * @param \stdClass $ruledata data to insert as new rule entry. - * @return \tool_monitor\rule object with rule id. + * + * @return rule An instance of rule class. */ public static function add_rule($ruledata) { - global $DB, $USER; - $now = time(); - $rule = new \stdClass(); - $rule->userid = empty($ruledata->userid) ? $USER->id : $ruledata->userid; - $rule->courseid = $ruledata->courseid; - $rule->name = $ruledata->name; - $rule->plugin = $ruledata->plugin; - $rule->eventname = $ruledata->eventname; - $rule->description = $ruledata->description; - $rule->frequency = (int)$ruledata->frequency; - $rule->message_template = $ruledata->message_template; - $rule->timewindow = $now; - $rule->timecreated = $now; - $rule->timemodified = $now; - $ruleid = $DB->insert_record('tool_monitor_rules', $rule, true); + global $DB; - return new rule($ruleid); + $now = time(); + $ruledata->timecreated = $now; + $ruledata->timemodified = $now; + + $ruledata->id = $DB->insert_record('tool_monitor_rules', $ruledata); + return new rule($ruledata); } /** - * Delete a rule and subscriptions by rule id. + * Clean data submitted by mform. + * + * @param \stdClass $mformdata data to insert as new rule entry. + * + * @return \stdClass Cleaned rule data. + */ + public static function clean_ruledata_form($mformdata) { + global $USER; + + $rule = new \stdClass(); + if (!empty($mformdata->ruleid)) { + $rule->id = $mformdata->ruleid; + } + $rule->userid = empty($mformdata->userid) ? $USER->id : $mformdata->userid; + $rule->courseid = $mformdata->courseid; + $rule->name = $mformdata->name; + $rule->plugin = $mformdata->plugin; + $rule->eventname = $mformdata->eventname; + $rule->description = $mformdata->description['text']; + $rule->descriptionformat = $mformdata->description['format']; + $rule->frequency = $mformdata->frequency; + $rule->timewindow = $mformdata->minutes * MINSECS; + $rule->template = $mformdata->template['text']; + $rule->templateformat = $mformdata->template['format']; + + return $rule; + } + + /** + * Delete a rule and associated subscriptions, by rule id. * * @param int $ruleid id of rule to be deleted. + * * @return bool */ public static function delete_rule($ruleid) { @@ -67,10 +96,11 @@ class rule_manager { } /** - * Get a rule object by id. + * Get an instance of rule class. * * @param \stdClass|int $ruleorid A rule object from database or rule id. - * @return \tool_monitor\rule object with rule id. + * + * @return rule object with rule id. */ public static function get_rule($ruleorid) { global $DB; @@ -86,35 +116,54 @@ class rule_manager { /** * Update rule data. * - * @throws coding_exception if $record->ruleid is invalid. - * @param object $params rule data to be updated. + * @throws \coding_exception if $record->ruleid is invalid. + * @param object $ruledata rule data to be updated. + * * @return bool */ - public static function update_rule($params) { + public static function update_rule($ruledata) { global $DB; - if (!self::get_rule($params->id)) { - throw new coding_exception('Invalid rule ID.'); + if (!self::get_rule($ruledata->id)) { + throw new \coding_exception('Invalid rule ID.'); } - $params->timemodified = time(); - return $DB->update_record('tool_monitor_rules', $params, false); + $ruledata->timemodified = time(); + return $DB->update_record('tool_monitor_rules', $ruledata); } /** * Get rules by course id. * * @param int $courseid course id of the rule. - * @return array rule data. + * @param int $limitfrom Limit from which to fetch rules. + * @param int $limitto Limit to which rules need to be fetched. + * + * @return array List of rules for the given course id, also includes system wide rules. */ - public static function get_rules_by_courseid($courseid) { + public static function get_rules_by_courseid($courseid, $limitfrom = 0, $limitto = 0) { global $DB; - return $DB->get_records('tool_monitor_rules', array('courseid' => $courseid)); + $select = "courseid = ? OR courseid = ?"; + return $DB->get_records_select('tool_monitor_rules', $select, array(0, $courseid), null, '*', $limitfrom, $limitto); + } + + /** + * Get rule count by course id. + * + * @param int $courseid course id of the rule. + * + * @return int count of rules present in system visible in the given course id. + */ + public static function count_rules_by_courseid($courseid) { + global $DB; + $select = "courseid = ? OR courseid = ?"; + return $DB->count_records_select('tool_monitor_rules', $select, array(0, $courseid)); } /** * Get rules by plugin name. * * @param string $plugin plugin name of the rule. - * @return array rule data. + * + * @return array List of rules for the given plugin name. */ public static function get_rules_by_plugin($plugin) { global $DB; @@ -125,10 +174,11 @@ class rule_manager { * Get rules by event name. * * @param string $eventname event name of the rule. - * @return array rule data. + * + * @return array List of rules for the given event. */ public static function get_rules_by_event($eventname) { global $DB; return $DB->get_records('tool_monitor_rules', array('eventname' => $eventname)); } -} \ No newline at end of file +} diff --git a/admin/tool/monitor/tests/generator/lib.php b/admin/tool/monitor/tests/generator/lib.php index 174d6938505..26c973dde66 100644 --- a/admin/tool/monitor/tests/generator/lib.php +++ b/admin/tool/monitor/tests/generator/lib.php @@ -45,7 +45,8 @@ class tool_monitor_generator extends testing_module_generator { * Function to generate rule data. * * @param \stdClass|array $record data to insert as rule entry. - * @return \tool_monitor\rule object. + * + * @return \tool_monitor\rule An instance of rule class. */ public function create_rule($record = null) { global $USER; @@ -67,14 +68,20 @@ class tool_monitor_generator extends testing_module_generator { if (!isset($record->description)) { $record->description = 'Rule description ' . $i; } + if (!isset($record->descriptionformat)) { + $record->descriptionformat = FORMAT_HTML; + } if (!isset($record->frequency)) { $record->frequency = 5; } if (!isset($record->minutes)) { $record->minutes = 5; } - if (!isset($record->message_template)) { - $record->message_template = 'Rule message template ' . $i; + if (!isset($record->template)) { + $record->template = 'Rule message template ' . $i; + } + if (!isset($record->templateformat)) { + $record->templateformat = FORMAT_HTML; } if (!isset($record->timewindow)) { $record->timewindow = $record->minutes * 60; @@ -92,6 +99,7 @@ class tool_monitor_generator extends testing_module_generator { $record->eventname = '\core\event\blog_entry_created'; } + unset($record->minutes); // Remove the minutes shortcut to the timewindow. return \tool_monitor\rule_manager::add_rule($record); } @@ -100,7 +108,8 @@ class tool_monitor_generator extends testing_module_generator { * * @throws coding_exception if $record->ruleid or $record->userid not present. * @param \stdClass|array $record data to insert as subscription entry. - * @return int subscription ID. + * + * @return \tool_monitor\subscription An instance of the subscription class. */ public function create_subscription($record = null) { @@ -120,15 +129,17 @@ class tool_monitor_generator extends testing_module_generator { throw new coding_exception('$record->userid must be present in tool_monitor_generator::create_subscription()'); } - return \tool_monitor\subscription_manager::create_subscription($record->ruleid, $record->courseid, + $sid = \tool_monitor\subscription_manager::create_subscription($record->ruleid, $record->courseid, $record->cmid, $record->userid); + return \tool_monitor\subscription_manager::get_subscription($sid); } /** * Function to generate event entries. * * @param \stdClass|array $record data to insert as event entry. - * @return \stdClass $record object with event id. + * + * @return \stdClass $record An object representing the newly created event entry. */ public function create_event_entries($record = null) { global $DB, $CFG; @@ -166,12 +177,13 @@ class tool_monitor_generator extends testing_module_generator { * Function to generate history data. * * @throws coding_exception if $record->sid or $record->userid not present. - * @param \stdClass $record data to insert as history entry. - * @return \stdClass $record object with history id. + * @param \stdClass|array $record data to insert as history entry. + * + * @return \stdClass $record An object representing the newly created history entry. */ public function create_history($record = null) { global $DB; - + $record = (object)(array)$record; if (!isset($record->sid)) { throw new coding_exception('subscription ID must be present in tool_monitor_generator::create_history() $record'); } diff --git a/admin/tool/monitor/tests/generator_test.php b/admin/tool/monitor/tests/generator_test.php index 18ebb9a018d..7e6403e71ad 100644 --- a/admin/tool/monitor/tests/generator_test.php +++ b/admin/tool/monitor/tests/generator_test.php @@ -18,20 +18,19 @@ * PHPUnit data generator tests. * * @package tool_monitor - * @category phpunit + * @category test * @copyright 2014 onwards Simey Lameze * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); - /** * PHPUnit data generator test case. * * @since Moodle 2.8 * @package tool_monitor - * @category phpunit + * @category test * @copyright 2014 onwards Simey Lameze * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ @@ -75,12 +74,16 @@ class tool_monitor_generator_testcase extends advanced_testcase { $record->userid = $user->id; $record->ruleid = $rule->id; - $sid = $monitorgenerator->create_subscription($record); - $subscription = \tool_monitor\subscription_manager::get_subscription($sid); + $subscription = $monitorgenerator->create_subscription($record); $this->assertEquals($record->courseid, $subscription->courseid); $this->assertEquals($record->ruleid, $subscription->ruleid); $this->assertEquals($record->userid, $subscription->userid); $this->assertEquals(0, $subscription->cmid); + + // Make sure rule id is always required. + $this->setExpectedException('coding_exception'); + unset($record->ruleid); + $monitorgenerator->create_subscription($record); } /** @@ -89,20 +92,16 @@ class tool_monitor_generator_testcase extends advanced_testcase { public function test_create_event_entries() { $this->setAdminUser(); $this->resetAfterTest(true); - $record = new \stdClass(); $context = \context_system::instance(); // Default data generator values. - $record->eventname = '\core\event\user_loggedin'; - $record->contextid = $context->id; - $record->contextlevel = $context->contextlevel; $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor'); // First create and assertdata using default values. $eventdata = $monitorgenerator->create_event_entries(); - $this->assertEquals($record->eventname, $eventdata->eventname); - $this->assertEquals($record->contextid, $eventdata->contextid); - $this->assertEquals($record->contextlevel, $eventdata->contextlevel); + $this->assertEquals('\core\event\user_loggedin', $eventdata->eventname); + $this->assertEquals($context->id, $eventdata->contextid); + $this->assertEquals($context->contextlevel, $eventdata->contextlevel); } /** @@ -118,8 +117,7 @@ class tool_monitor_generator_testcase extends advanced_testcase { $record = new \stdClass(); $record->userid = $user->id; $record->ruleid = $rule->id; - $sid = $monitorgenerator->create_subscription($record); - \tool_monitor\subscription_manager::get_subscription($sid); + $sid = $monitorgenerator->create_subscription($record)->id; $record->sid = $sid; $historydata = $monitorgenerator->create_history($record); $this->assertEquals($record->userid, $historydata->userid); diff --git a/admin/tool/monitor/tests/rule_manager_test.php b/admin/tool/monitor/tests/rule_manager_test.php index b75d17e916b..f9e05dc15d8 100644 --- a/admin/tool/monitor/tests/rule_manager_test.php +++ b/admin/tool/monitor/tests/rule_manager_test.php @@ -18,7 +18,7 @@ * Unit tests for rule manager api. * * @package tool_monitor - * @category phpunit + * @category test * @copyright 2014 onwards Simey Lameze * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ @@ -27,7 +27,12 @@ defined('MOODLE_INTERNAL') || die(); global $CFG; -class rule_manager_testcase extends advanced_testcase { +/** + * Tests for rule manager. + * + * Class tool_monitor_rule_manager_testcase + */ +class tool_monitor_rule_manager_testcase extends advanced_testcase { /** * Test add_rule method. @@ -40,25 +45,25 @@ class rule_manager_testcase extends advanced_testcase { $course = $this->getDataGenerator()->create_course(); $now = time(); - $rule = new \stdClass(); + $rule = new stdClass(); $rule->userid = $user->id; $rule->courseid = $course->id; $rule->name = 'test rule 1'; $rule->plugin = 'core'; $rule->eventname = '\core\event\course_updated'; $rule->description = 'test description 1'; + $rule->descriptionformat = FORMAT_HTML; $rule->frequency = 15; - $rule->message_template = 'test template message'; - $rule->timewindow = null; + $rule->template = 'test template message'; + $rule->templateformat = FORMAT_HTML; + $rule->timewindow = 300; $rule->timecreated = $now; $rule->timemodified = $now; $ruledata = \tool_monitor\rule_manager::add_rule($rule); - - $this->assertEquals($rule->eventname, $ruledata->eventname); - $this->assertEquals($rule->userid, $ruledata->userid); - $this->assertEquals($rule->courseid, $ruledata->courseid); - + foreach ($rule as $prop => $value) { + $this->assertEquals($ruledata->$prop, $value); + } } /** @@ -72,6 +77,7 @@ class rule_manager_testcase extends advanced_testcase { $rule = $monitorgenerator->create_rule(); $rules1 = \tool_monitor\rule_manager::get_rule($rule->id); $this->assertInstanceOf('tool_monitor\rule', $rules1); + $this->assertEquals($rules1, $rule); } /** @@ -89,7 +95,7 @@ class rule_manager_testcase extends advanced_testcase { $ruledata->frequency = 25; \tool_monitor\rule_manager::update_rule($ruledata); - $this->assertNotEquals($ruledata->frequency, $rule->frequency); + $this->assertEquals(25, $ruledata->frequency); } @@ -101,9 +107,24 @@ class rule_manager_testcase extends advanced_testcase { $this->resetAfterTest(true); $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor'); - $rule = $monitorgenerator->create_rule(); - $ruledata = \tool_monitor\rule_manager::get_rules_by_courseid($rule->courseid); - $this->assertEquals($rule->courseid, 0); + + $record = new stdClass(); + $record->courseid = 3; + + $record2 = new stdClass(); + $record2->courseid = 4; + + $ruleids = array(); + for ($i = 0; $i < 10; $i++) { + $rule = $monitorgenerator->create_rule($record); + $ruleids[] = $rule->id; + $rule = $monitorgenerator->create_rule(); // Create some site level rules. + $ruleids[] = $rule->id; + $rule = $monitorgenerator->create_rule($record2); // Create rules in a different course. + } + $ruledata = \tool_monitor\rule_manager::get_rules_by_courseid(3); + $this->assertEquals($ruleids, array_keys($ruledata)); + $this->assertCount(20, $ruledata); } /** @@ -114,9 +135,23 @@ class rule_manager_testcase extends advanced_testcase { $this->resetAfterTest(true); $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor'); - $rule = $monitorgenerator->create_rule(); - $rules1 = \tool_monitor\rule_manager::get_rules_by_plugin($rule->plugin); - $this->assertEquals(1, count($rules1)); + + $record = new stdClass(); + $record->plugin = 'core'; + + $record2 = new stdClass(); + $record2->plugin = 'mod_assign'; + + $ruleids = array(); + for ($i = 0; $i < 10; $i++) { + $rule = $monitorgenerator->create_rule($record); + $ruleids[] = $rule->id; + $rule = $monitorgenerator->create_rule($record2); // Create rules in a different plugin. + } + + $ruledata = \tool_monitor\rule_manager::get_rules_by_plugin('core'); + $this->assertEquals($ruleids, array_keys($ruledata)); + $this->assertCount(10, $ruledata); } /** @@ -128,7 +163,22 @@ class rule_manager_testcase extends advanced_testcase { $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor'); $rule = $monitorgenerator->create_rule(); - $rules1 = \tool_monitor\rule_manager::get_rules_by_event($rule->eventname); - $this->assertEquals(1, count($rules1)); + + $record = new stdClass(); + $record->eventname = '\core\event\calendar_event_created'; + + $record2 = new stdClass(); + $record2->eventname = '\core\event\calendar_event_updated'; + + $ruleids = array(); + for ($i = 0; $i < 10; $i++) { + $rule = $monitorgenerator->create_rule($record); + $ruleids[] = $rule->id; + $rule = $monitorgenerator->create_rule($record2); // Create rules in a different plugin. + } + + $ruledata = \tool_monitor\rule_manager::get_rules_by_event('\core\event\calendar_event_created'); + $this->assertEmpty(array_diff(array_keys($ruledata), $ruleids)); + $this->assertCount(10, $ruledata); } } \ No newline at end of file From 48cc3a8d4d933f1a43808da5beb4449019893c88 Mon Sep 17 00:00:00 2001 From: Simey Lameze Date: Fri, 4 Jul 2014 10:28:27 +0800 Subject: [PATCH 10/44] MDL-45758 tool_monitor: Initial version of rule form. Original issue - MDL-45938 --- admin/tool/monitor/classes/rule_form.php | 74 +++++++++++++++ admin/tool/monitor/edit.php | 109 +++++++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 admin/tool/monitor/classes/rule_form.php create mode 100644 admin/tool/monitor/edit.php diff --git a/admin/tool/monitor/classes/rule_form.php b/admin/tool/monitor/classes/rule_form.php new file mode 100644 index 00000000000..95aab3e4ee5 --- /dev/null +++ b/admin/tool/monitor/classes/rule_form.php @@ -0,0 +1,74 @@ + + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @package tool_monitor + */ +namespace tool_monitor; + +require_once($CFG->dirroot.'/lib/formslib.php'); + +class rule_form extends \moodleform { + + function definition () { + global $CFG, $USER, $OUTPUT; + $mform = $this->_form; + + // General section header + $mform->addElement('header', 'general', get_string('general')); + // Hidden rule ID + $mform->addElement('hidden', 'ruleid'); + $mform->setType('ruleid', PARAM_INT); + $mform->setDefault('ruleid', ''); + // Hidden course ID + $mform->addElement('hidden', 'courseid'); + $mform->setType('courseid', PARAM_INT); + $mform->setDefault('courseid', ''); + // Name field + $mform->addElement('text', 'name', get_string('name','report_monitor'), 'size="50"'); + $mform->addRule('name', get_string('required'), 'required'); + $mform->setType('name', PARAM_TEXT); + $mform->addHelpButton('name', 'name', 'report_monitor'); + // Plugin field + $mform->addElement('select', 'plugin', get_string('plugin', 'report_monitor'), $pluginslist); + $mform->addRule('plugin', get_string('required'), 'required'); + $mform->addHelpButton('plugin', 'plugin', 'report_monitor'); + // Event field + $mform->addElement('select', 'event', get_string('event', 'report_monitor'), $eventoption); + $mform->addRule('event', get_string('required'), 'required'); + $mform->addHelpButton('event', 'event', 'report_monitor'); + // Description field + $mform->addElement('editor', 'description', get_string('description', 'report_monitor')); + $mform->addHelpButton('description', 'description', 'report_monitor'); + // Customize your trigger section + $mform->addElement('header', 'customize', get_string('customize', 'report_monitor')); + // Call the filters + $filter = new filter_manager(); + foreach ($filter->get_filters() as $filterobj) { + $filterobj->add_form_elements($mform); + } + // Customize your trigger message section + $mform->addElement('header', 'message', get_string('message_header', 'report_monitor')); + // Message template field + $mform->addElement('editor', 'message_template', get_string('message_template', 'report_monitor')); + $mform->setDefault('message_template', get_string('defaultmessagetpl', 'report_monitor')); + $mform->addRule('message_template', get_string('required'), 'required'); + $mform->addHelpButton('message_template', 'message_template', 'report_monitor'); + // Submit button + $this->add_action_buttons(false, get_string('savechanges')); + } + + /** + * Form validation + * + * @param array $data data from the form. + * @param array $files files uploaded. + * @return array of errors. + */ + function validation($data, $files) { + + } +} +?> \ No newline at end of file diff --git a/admin/tool/monitor/edit.php b/admin/tool/monitor/edit.php new file mode 100644 index 00000000000..558821c721d --- /dev/null +++ b/admin/tool/monitor/edit.php @@ -0,0 +1,109 @@ +. + +/** + * This file gives an overview of the monitors present in site. + * + * @package tool_monitor + * @copyright 2014 onwards Simey Lameze + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +require('../../config.php'); +require_once($CFG->libdir.'/adminlib.php'); +require_once($CFG->dirroot.'/course/lib.php'); +require_once('locallib.php'); + +$ruleid = optional_param('ruleid', 0, PARAM_INT); +$courseid = optional_param('id', 0, PARAM_INT); + +$ruledata = new \stdClass(); + +// Validate course id +if (empty($courseid)) { + require_login(); + $context = context_system::instance(); + $coursename = format_string($SITE->fullname, true, array('context' => $context)); + $PAGE->set_context($context); +} else { + $course = get_course($courseid); + $ruledata->courseid = $course->id; + require_login($course); + $context = context_course::instance($course->id); + $coursename = format_string($course->fullname, true, array('context' => $context)); +} +require_capability('tool/monitor:managerules', $context); + +// Get rule data to edit form +if ($ruleid) { + $rule = \tool_monitor\rule_manager::get_rule($ruleid); + + $ruledata->ruleid = $rule->id; + $ruledata->courseid = $rule->courseid; + $ruledata->name = $rule->name; + $ruledata->plugin = $rule->plugin; + $ruledata->event = $rule->event; + $ruledata->description['text'] = $rule->description; + $ruledata->rule['frequency'] = $rule->frequency; + $ruledata->rule['minutes'] = $rule->minutes; + $ruledata->message_template['text'] = $rule->message_template; +} + +// Set up the page. +$a = new stdClass(); +$a->coursename = $coursename; +$a->reportname = get_string('pluginname', 'tool_monitor'); +$title = get_string('title', 'tool_monitor', $a); +$url = new moodle_url("/admin/tool/monitor/edit.php", array('id' => $courseid)); +$indexurl = new moodle_url("/admin/tool/monitor/index.php", array('id' => $courseid)); + +$PAGE->set_url($url); +$PAGE->set_pagelayout('report'); +$PAGE->set_title($title); +$PAGE->set_heading($title); +$PAGE->requires->js('/tool/monitor/event.js'); + +// Site level report. +if (empty($courseid)) { + admin_externalpage_setup('toolmonitorrules', '', null, '', array('pagelayout' => 'report')); +} + +$mform = new tool_monitor\rule_form(); +if ($mformdata = $mform->get_data()) { + $ruledata = new \stdClass(); + $ruledata->courseid = $mformdata->courseid; + $ruledata->name = $mformdata->name; + $ruledata->plugin = $mformdata->plugin; + $ruledata->event = $mformdata->event; + $ruledata->description = $mformdata->description['text']; + $ruledata->frequency = $mformdata->rule['frequency']; + $ruledata->minutes = $mformdata->rule['minutes']; + $ruledata->message_template = $mformdata->message_template['text']; + + if (empty($mformdata->ruleid)) { + \tool_monitor\rule_manager::add_rule($ruledata); + } else { + $ruledata->id = $mformdata->ruleid; + \tool_monitor\rule_manager::update_rule($ruledata); + } + $courseid = $mformdata->courseid; + $url = new moodle_url("/admin/tool/monitor/managerules.php", array('id' => $courseid)); + redirect($url); +} else { + echo $OUTPUT->header(); + $mform->set_data($ruledata); + $mform->display(); +} +echo $OUTPUT->footer(); \ No newline at end of file From 2fd010b88642a51e1058acacc227279754f4111c Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Thu, 10 Jul 2014 14:48:37 +0800 Subject: [PATCH 11/44] MDL-45758 tool_monitor: YUI module to handle event selection dropdown Original issue - MDL-45938 --- .../moodle-tool_monitor-dropdown-debug.js | 92 +++++++++++++++++++ .../moodle-tool_monitor-dropdown-min.js | 1 + .../moodle-tool_monitor-dropdown.js | 92 +++++++++++++++++++ .../tool/monitor/yui/src/dropdown/build.json | 10 ++ .../monitor/yui/src/dropdown/js/dropdown.js | 87 ++++++++++++++++++ .../yui/src/dropdown/meta/dropdown.json | 9 ++ 6 files changed, 291 insertions(+) create mode 100644 admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-debug.js create mode 100644 admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-min.js create mode 100644 admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown.js create mode 100644 admin/tool/monitor/yui/src/dropdown/build.json create mode 100644 admin/tool/monitor/yui/src/dropdown/js/dropdown.js create mode 100644 admin/tool/monitor/yui/src/dropdown/meta/dropdown.json diff --git a/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-debug.js b/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-debug.js new file mode 100644 index 00000000000..992c45be5b4 --- /dev/null +++ b/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-debug.js @@ -0,0 +1,92 @@ +YUI.add('moodle-tool_monitor-dropdown', function (Y, NAME) { + +/** + * A module to manage dropdowns on the rule add/edit form. + * + * @module moodle-tool_monitor-dropdown + */ + +/** + * A module to manage dependent selects on the edit page. + * + * @since Moodle 2.8 + * @class moodle-tool_monitor.dropdown + * @extends Base + * @constructor + */ +function DropDown() { + DropDown.superclass.constructor.apply(this, arguments); +} + + +var SELECTORS = { + PLUGIN: '#id_plugin', + EVENTNAME: '#id_eventname', + OPTION: 'option', + CHOOSE: 'option[value=""]' + }; + +Y.extend(DropDown, Y.Base, { + + /** + * Reference to the plugin node. + * + * @property plugin + * @type Object + * @default null + * @protected + */ + plugin: null, + + /** + * Reference to the plugin node. + * + * @property eventname + * @type Object + * @default null + * @protected + */ + eventname: null, + + /** + * Initializer. + * Basic setup and delegations. + * + * @method initializer + */ + initializer: function() { + this.plugin = Y.one(SELECTORS.PLUGIN); + this.eventname = Y.one(SELECTORS.EVENTNAME); + this.plugin.on('change', this.updateEventsList, this); + }, + + /** + * Method to update the events list drop down when plugin list drop down is changed. + * + * @method updateEventsList + */ + updateEventsList: function() { + var plugin = this.plugin.get('value'); // Get component name. + var namespace = '\\' + plugin + '\\'; + this.eventname.all(SELECTORS.OPTION).hide(); // Hide all options. + this.eventname.all(SELECTORS.OPTION).each(function(node) { + // Make sure we highlight only nodes with correct namespace. + if (node.get('value').substring(0, namespace.length) === namespace) { + node.show(); + } + }); + // Mark the default choose node as visible and selected. + var choosenode = this.eventname.one(SELECTORS.CHOOSE); + choosenode.show().set('selected', 'selected'); + } +}, { + NAME: 'dropDown', + ATTRS: {} +}); + +Y.namespace('M.tool_monitor.DropDown').init = function(config) { + return new DropDown(config); +}; + + +}, '@VERSION@', {"requires": ["base", "event", "node"]}); diff --git a/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-min.js b/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-min.js new file mode 100644 index 00000000000..a95a95e6f06 --- /dev/null +++ b/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-min.js @@ -0,0 +1 @@ +YUI.add("moodle-tool_monitor-dropdown",function(e,t){function n(){n.superclass.constructor.apply(this,arguments)}var r={PLUGIN:"#id_plugin",EVENTNAME:"#id_eventname",OPTION:"option",CHOOSE:'option[value=""]'};e.extend(n,e.Base,{plugin:null,eventname:null,initializer:function(){this.plugin=e.one(r.PLUGIN),this.eventname=e.one(r.EVENTNAME),this.plugin.on("change",this.updateEventsList,this)},updateEventsList:function(){var e=this.plugin.get("value"),t="\\"+e+"\\";this.eventname.all(r.OPTION).hide(),this.eventname.all(r.OPTION).each(function(e){e.get("value").substring(0,t.length)===t&&e.show()});var n=this.eventname.one(r.CHOOSE);n.show().set("selected","selected")}},{NAME:"dropDown",ATTRS:{}}),e.namespace("M.tool_monitor.DropDown").init=function(e){return new n(e)}},"@VERSION@",{requires:["base","event","node"]}); diff --git a/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown.js b/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown.js new file mode 100644 index 00000000000..992c45be5b4 --- /dev/null +++ b/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown.js @@ -0,0 +1,92 @@ +YUI.add('moodle-tool_monitor-dropdown', function (Y, NAME) { + +/** + * A module to manage dropdowns on the rule add/edit form. + * + * @module moodle-tool_monitor-dropdown + */ + +/** + * A module to manage dependent selects on the edit page. + * + * @since Moodle 2.8 + * @class moodle-tool_monitor.dropdown + * @extends Base + * @constructor + */ +function DropDown() { + DropDown.superclass.constructor.apply(this, arguments); +} + + +var SELECTORS = { + PLUGIN: '#id_plugin', + EVENTNAME: '#id_eventname', + OPTION: 'option', + CHOOSE: 'option[value=""]' + }; + +Y.extend(DropDown, Y.Base, { + + /** + * Reference to the plugin node. + * + * @property plugin + * @type Object + * @default null + * @protected + */ + plugin: null, + + /** + * Reference to the plugin node. + * + * @property eventname + * @type Object + * @default null + * @protected + */ + eventname: null, + + /** + * Initializer. + * Basic setup and delegations. + * + * @method initializer + */ + initializer: function() { + this.plugin = Y.one(SELECTORS.PLUGIN); + this.eventname = Y.one(SELECTORS.EVENTNAME); + this.plugin.on('change', this.updateEventsList, this); + }, + + /** + * Method to update the events list drop down when plugin list drop down is changed. + * + * @method updateEventsList + */ + updateEventsList: function() { + var plugin = this.plugin.get('value'); // Get component name. + var namespace = '\\' + plugin + '\\'; + this.eventname.all(SELECTORS.OPTION).hide(); // Hide all options. + this.eventname.all(SELECTORS.OPTION).each(function(node) { + // Make sure we highlight only nodes with correct namespace. + if (node.get('value').substring(0, namespace.length) === namespace) { + node.show(); + } + }); + // Mark the default choose node as visible and selected. + var choosenode = this.eventname.one(SELECTORS.CHOOSE); + choosenode.show().set('selected', 'selected'); + } +}, { + NAME: 'dropDown', + ATTRS: {} +}); + +Y.namespace('M.tool_monitor.DropDown').init = function(config) { + return new DropDown(config); +}; + + +}, '@VERSION@', {"requires": ["base", "event", "node"]}); diff --git a/admin/tool/monitor/yui/src/dropdown/build.json b/admin/tool/monitor/yui/src/dropdown/build.json new file mode 100644 index 00000000000..66630f69de2 --- /dev/null +++ b/admin/tool/monitor/yui/src/dropdown/build.json @@ -0,0 +1,10 @@ +{ + "name": "moodle-tool_monitor-dropdown", + "builds": { + "moodle-tool_monitor-dropdown": { + "jsfiles": [ + "dropdown.js" + ] + } + } +} diff --git a/admin/tool/monitor/yui/src/dropdown/js/dropdown.js b/admin/tool/monitor/yui/src/dropdown/js/dropdown.js new file mode 100644 index 00000000000..00a53764e49 --- /dev/null +++ b/admin/tool/monitor/yui/src/dropdown/js/dropdown.js @@ -0,0 +1,87 @@ +/** + * A module to manage dropdowns on the rule add/edit form. + * + * @module moodle-tool_monitor-dropdown + */ + +/** + * A module to manage dependent selects on the edit page. + * + * @since Moodle 2.8 + * @class moodle-tool_monitor.dropdown + * @extends Base + * @constructor + */ +function DropDown() { + DropDown.superclass.constructor.apply(this, arguments); +} + + +var SELECTORS = { + PLUGIN: '#id_plugin', + EVENTNAME: '#id_eventname', + OPTION: 'option', + CHOOSE: 'option[value=""]' + }; + +Y.extend(DropDown, Y.Base, { + + /** + * Reference to the plugin node. + * + * @property plugin + * @type Object + * @default null + * @protected + */ + plugin: null, + + /** + * Reference to the plugin node. + * + * @property eventname + * @type Object + * @default null + * @protected + */ + eventname: null, + + /** + * Initializer. + * Basic setup and delegations. + * + * @method initializer + */ + initializer: function() { + this.plugin = Y.one(SELECTORS.PLUGIN); + this.eventname = Y.one(SELECTORS.EVENTNAME); + this.plugin.on('change', this.updateEventsList, this); + }, + + /** + * Method to update the events list drop down when plugin list drop down is changed. + * + * @method updateEventsList + */ + updateEventsList: function() { + var plugin = this.plugin.get('value'); // Get component name. + var namespace = '\\' + plugin + '\\'; + this.eventname.all(SELECTORS.OPTION).hide(); // Hide all options. + this.eventname.all(SELECTORS.OPTION).each(function(node) { + // Make sure we highlight only nodes with correct namespace. + if (node.get('value').substring(0, namespace.length) === namespace) { + node.show(); + } + }); + // Mark the default choose node as visible and selected. + var choosenode = this.eventname.one(SELECTORS.CHOOSE); + choosenode.show().set('selected', 'selected'); + } +}, { + NAME: 'dropDown', + ATTRS: {} +}); + +Y.namespace('M.tool_monitor.DropDown').init = function(config) { + return new DropDown(config); +}; diff --git a/admin/tool/monitor/yui/src/dropdown/meta/dropdown.json b/admin/tool/monitor/yui/src/dropdown/meta/dropdown.json new file mode 100644 index 00000000000..34fa63f143d --- /dev/null +++ b/admin/tool/monitor/yui/src/dropdown/meta/dropdown.json @@ -0,0 +1,9 @@ +{ + "moodle-tool_monitor-dropdown": { + "requires": [ + "base", + "event", + "node" + ] + } +} From 58097ddf9b784c5cf3afdd535653b84be19bf29d Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Thu, 10 Jul 2014 14:49:00 +0800 Subject: [PATCH 12/44] MDL-45758 tool_monitor: Add support for editing/creating a rule Original issue - MDL-45938 --- admin/tool/monitor/classes/rule.php | 2 +- admin/tool/monitor/classes/rule_form.php | 162 ++++++++++++++------ admin/tool/monitor/edit.php | 80 ++++------ admin/tool/monitor/lang/en/tool_monitor.php | 29 ++++ admin/tool/monitor/managerules.php | 0 5 files changed, 183 insertions(+), 90 deletions(-) create mode 100644 admin/tool/monitor/managerules.php diff --git a/admin/tool/monitor/classes/rule.php b/admin/tool/monitor/classes/rule.php index 9d23cbdff91..0aeb34f0283 100644 --- a/admin/tool/monitor/classes/rule.php +++ b/admin/tool/monitor/classes/rule.php @@ -117,7 +117,7 @@ class rule { } } } - $url = new \moodle_url($CFG->wwwroot. '/tool/monitor/index.php', array('id' => $courseid, 'ruleid' => $this->id, + $url = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/index.php', array('courseid' => $courseid, 'ruleid' => $this->id, 'action' => 'subscribe')); return new \single_select($url, 'cmid', $options, '', $nothing = array('' => 'choosedots')); } diff --git a/admin/tool/monitor/classes/rule_form.php b/admin/tool/monitor/classes/rule_form.php index 95aab3e4ee5..99b3c8de892 100644 --- a/admin/tool/monitor/classes/rule_form.php +++ b/admin/tool/monitor/classes/rule_form.php @@ -1,62 +1,132 @@ . + /** - * The mform for creating and editing a rule + * The mform for creating and editing a rule. * * @copyright 2014 onwards Simey Lameze - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @package tool_monitor + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @package tool_monitor */ + namespace tool_monitor; require_once($CFG->dirroot.'/lib/formslib.php'); +/** + * The mform for creating and editing a rule. + * + * @since Moodle 2.8 + * @copyright 2014 onwards Simey Lameze + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @package tool_monitor + */ class rule_form extends \moodleform { - function definition () { - global $CFG, $USER, $OUTPUT; + /** + * Mform class definition + * + */ + public function definition () { $mform = $this->_form; + $eventlist = $this->_customdata['eventlist']; + $pluginlist = $this->_customdata['pluginlist']; + $rule = $this->_customdata['rule']; + $courseid = $this->_customdata['courseid']; + $eventlist = array_merge(array('' => get_string('choosedots')), $eventlist); + $pluginlist = array_merge(array('' => get_string('choosedots')), $pluginlist); - // General section header + // General section header. $mform->addElement('header', 'general', get_string('general')); - // Hidden rule ID - $mform->addElement('hidden', 'ruleid'); - $mform->setType('ruleid', PARAM_INT); - $mform->setDefault('ruleid', ''); - // Hidden course ID + + // Hidden course ID. $mform->addElement('hidden', 'courseid'); $mform->setType('courseid', PARAM_INT); - $mform->setDefault('courseid', ''); - // Name field - $mform->addElement('text', 'name', get_string('name','report_monitor'), 'size="50"'); + + // We are editing a existing rule. + if (!empty($rule->id)) { + // Hidden rule id. + $mform->addElement('hidden', 'ruleid'); + $mform->setType('ruleid', PARAM_INT); + $mform->setConstant('ruleid', $rule->id); + + // Force course id. + $courseid = $rule->courseid; + } + + // Make course id a constant. + $mform->setConstant('courseid', $courseid); + + if (empty($courseid)) { + $context = \context_system::instance(); + } else { + $context = \context_course::instance($courseid); + } + + $editoroptions = array( + 'subdirs' => 0, + 'maxbytes' => 0, + 'maxfiles' => 0, + 'changeformat' => 0, + 'context' => $context, + 'noclean' => 0, + 'trusttext' => 0 + ); + + // Name field. + $mform->addElement('text', 'name', get_string('name', 'tool_monitor'), 'size="50"'); $mform->addRule('name', get_string('required'), 'required'); $mform->setType('name', PARAM_TEXT); - $mform->addHelpButton('name', 'name', 'report_monitor'); - // Plugin field - $mform->addElement('select', 'plugin', get_string('plugin', 'report_monitor'), $pluginslist); + $mform->addHelpButton('name', 'name', 'tool_monitor'); + + // Plugin field. + $mform->addElement('select', 'plugin', get_string('selectplugin', 'tool_monitor'), $pluginlist); $mform->addRule('plugin', get_string('required'), 'required'); - $mform->addHelpButton('plugin', 'plugin', 'report_monitor'); - // Event field - $mform->addElement('select', 'event', get_string('event', 'report_monitor'), $eventoption); - $mform->addRule('event', get_string('required'), 'required'); - $mform->addHelpButton('event', 'event', 'report_monitor'); - // Description field - $mform->addElement('editor', 'description', get_string('description', 'report_monitor')); - $mform->addHelpButton('description', 'description', 'report_monitor'); - // Customize your trigger section - $mform->addElement('header', 'customize', get_string('customize', 'report_monitor')); - // Call the filters - $filter = new filter_manager(); - foreach ($filter->get_filters() as $filterobj) { - $filterobj->add_form_elements($mform); - } - // Customize your trigger message section - $mform->addElement('header', 'message', get_string('message_header', 'report_monitor')); - // Message template field - $mform->addElement('editor', 'message_template', get_string('message_template', 'report_monitor')); - $mform->setDefault('message_template', get_string('defaultmessagetpl', 'report_monitor')); - $mform->addRule('message_template', get_string('required'), 'required'); - $mform->addHelpButton('message_template', 'message_template', 'report_monitor'); - // Submit button + $mform->addHelpButton('plugin', 'selectplugin', 'tool_monitor'); + + // Event field. + $mform->addElement('select', 'eventname', get_string('selectevent', 'tool_monitor'), $eventlist); + $mform->addRule('eventname', get_string('required'), 'required'); + $mform->addHelpButton('eventname', 'selectevent', 'tool_monitor'); + + // Description field. + $mform->addElement('editor', 'description', get_string('description', 'tool_monitor'), $editoroptions); + $mform->addHelpButton('description', 'description', 'tool_monitor'); + + // Filters. + $mform->addElement('header', 'customizefilters', get_string('customizefilters', 'tool_monitor')); + $freq = array(1 => 1, 5 => 5, 10 => 10, 20 => 20, 30 => 30, 40 => 40, 50 => 50, 60 => 60, 70 => 70, 80 => 80, 90 => 90, + 100 => 100, 1000 => 1000); + $mform->addElement('select', 'frequency', get_string('selectfrequency', 'tool_monitor'), $freq); + $mform->addRule('frequency', get_string('required'), 'required'); + $mform->addHelpButton('frequency', 'selectfrequency', 'tool_monitor'); + + $mins = array(1 => 1, 5 => 5, 10 => 10, 15 => 15, 20 => 20, 25 => 25, 30 => 30, 35 => 35, 40 => 40, 45 => 45, 50 => 50, + 55 => 55, 60 => 60); + $mform->addElement('select', 'minutes', get_string('selectminutes', 'tool_monitor'), $mins); + $mform->addRule('minutes', get_string('required'), 'required'); + + // Message template. + $mform->addElement('header', 'customizemessage', get_string('customizemessage', 'tool_monitor')); + $mform->addElement('editor', 'template', get_string('messagetemplate', 'tool_monitor'), $editoroptions); + $mform->setDefault('template', get_string('defaultmessagetpl', 'tool_monitor')); + $mform->addRule('template', get_string('required'), 'required'); + $mform->addHelpButton('template', 'messagetemplate', 'tool_monitor'); + + // Action buttons. $this->add_action_buttons(false, get_string('savechanges')); } @@ -65,10 +135,16 @@ class rule_form extends \moodleform { * * @param array $data data from the form. * @param array $files files uploaded. + * * @return array of errors. */ - function validation($data, $files) { + public function validation($data, $files) { + $errors = parent::validation($data, $files); + if (!eventlist::validate_event_plugin($data['plugin'], $data['eventname'])) { + $errors['eventname'] = get_string('errorincorrectevent', 'tool_monitor'); + } + + return $errors; } -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/admin/tool/monitor/edit.php b/admin/tool/monitor/edit.php index 558821c721d..8722da35d2d 100644 --- a/admin/tool/monitor/edit.php +++ b/admin/tool/monitor/edit.php @@ -21,17 +21,13 @@ * @copyright 2014 onwards Simey Lameze * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -require('../../config.php'); +require(__DIR__ . '/../../../config.php'); require_once($CFG->libdir.'/adminlib.php'); -require_once($CFG->dirroot.'/course/lib.php'); -require_once('locallib.php'); $ruleid = optional_param('ruleid', 0, PARAM_INT); -$courseid = optional_param('id', 0, PARAM_INT); +$courseid = optional_param('courseid', 0, PARAM_INT); -$ruledata = new \stdClass(); - -// Validate course id +// Validate course id. if (empty($courseid)) { require_login(); $context = context_system::instance(); @@ -39,71 +35,63 @@ if (empty($courseid)) { $PAGE->set_context($context); } else { $course = get_course($courseid); - $ruledata->courseid = $course->id; require_login($course); $context = context_course::instance($course->id); $coursename = format_string($course->fullname, true, array('context' => $context)); } + +// Check for caps. require_capability('tool/monitor:managerules', $context); -// Get rule data to edit form -if ($ruleid) { - $rule = \tool_monitor\rule_manager::get_rule($ruleid); - - $ruledata->ruleid = $rule->id; - $ruledata->courseid = $rule->courseid; - $ruledata->name = $rule->name; - $ruledata->plugin = $rule->plugin; - $ruledata->event = $rule->event; - $ruledata->description['text'] = $rule->description; - $ruledata->rule['frequency'] = $rule->frequency; - $ruledata->rule['minutes'] = $rule->minutes; - $ruledata->message_template['text'] = $rule->message_template; -} - // Set up the page. $a = new stdClass(); $a->coursename = $coursename; $a->reportname = get_string('pluginname', 'tool_monitor'); $title = get_string('title', 'tool_monitor', $a); -$url = new moodle_url("/admin/tool/monitor/edit.php", array('id' => $courseid)); -$indexurl = new moodle_url("/admin/tool/monitor/index.php", array('id' => $courseid)); +$url = new moodle_url("/admin/tool/monitor/edit.php", array('courseid' => $courseid, 'ruleid' => $ruleid)); +$manageurl = new moodle_url("/admin/tool/monitor/managerules.php", array('courseid' => $courseid)); $PAGE->set_url($url); $PAGE->set_pagelayout('report'); $PAGE->set_title($title); $PAGE->set_heading($title); -$PAGE->requires->js('/tool/monitor/event.js'); +$PAGE->requires->yui_module('moodle-tool_monitor-dropdown', 'Y.M.tool_monitor.DropDown.init'); // Site level report. if (empty($courseid)) { admin_externalpage_setup('toolmonitorrules', '', null, '', array('pagelayout' => 'report')); +} else { + // Course level report. + $PAGE->navigation->override_active_url($manageurl); } -$mform = new tool_monitor\rule_form(); -if ($mformdata = $mform->get_data()) { - $ruledata = new \stdClass(); - $ruledata->courseid = $mformdata->courseid; - $ruledata->name = $mformdata->name; - $ruledata->plugin = $mformdata->plugin; - $ruledata->event = $mformdata->event; - $ruledata->description = $mformdata->description['text']; - $ruledata->frequency = $mformdata->rule['frequency']; - $ruledata->minutes = $mformdata->rule['minutes']; - $ruledata->message_template = $mformdata->message_template['text']; +// Get data ready for mform. +$eventlist = tool_monitor\eventlist::get_all_eventlist(true); +$pluginlist = tool_monitor\eventlist::get_plugin_list(); +if (!empty($ruleid)) { + $rule = \tool_monitor\rule_manager::get_rule($ruleid)->get_mform_set_data(); + $rule->minutes = $rule->timewindow / MINSECS; +} else { + $rule = new stdClass(); +} - if (empty($mformdata->ruleid)) { - \tool_monitor\rule_manager::add_rule($ruledata); +$mform = new tool_monitor\rule_form(null, array('eventlist' => $eventlist, 'pluginlist' => $pluginlist, 'rule' => $rule, + 'courseid' => $courseid)); + +if ($mformdata = $mform->get_data()) { + $rule = \tool_monitor\rule_manager::clean_ruledata_form($mformdata); + + if (empty($rule->id)) { + \tool_monitor\rule_manager::add_rule($rule); } else { - $ruledata->id = $mformdata->ruleid; - \tool_monitor\rule_manager::update_rule($ruledata); + \tool_monitor\rule_manager::update_rule($rule); } - $courseid = $mformdata->courseid; - $url = new moodle_url("/admin/tool/monitor/managerules.php", array('id' => $courseid)); - redirect($url); + + redirect($manageurl); } else { echo $OUTPUT->header(); - $mform->set_data($ruledata); + $mform->set_data($rule); $mform->display(); + echo $OUTPUT->footer(); } -echo $OUTPUT->footer(); \ No newline at end of file + diff --git a/admin/tool/monitor/lang/en/tool_monitor.php b/admin/tool/monitor/lang/en/tool_monitor.php index 4c59a8c8013..9b1e7e55221 100644 --- a/admin/tool/monitor/lang/en/tool_monitor.php +++ b/admin/tool/monitor/lang/en/tool_monitor.php @@ -27,11 +27,40 @@ $string['allevents'] = 'All events'; $string['allmodules'] = 'All modules'; $string['core'] = 'Core'; +$string['customizefilters'] = 'Select the frequency of the events'; +$string['customizemessage'] = 'Cutomize the notification message'; +$string['description'] = 'Description:'; +$string['description_help'] = "Description is displayed to users when they want to subscribe to this rule. This helps them understand what the rule is about."; +$string['defaultmessagetpl'] = 'Rule "{rulename}" has happened. You can find further details at {link}'; $string['eventnotfound'] = 'Event not found'; +$string['errorincorrectevent'] = 'Please select an event related to the selected plugin'; $string['freqdesc'] = '{$a->freq} times in {$a->mins} minutes'; $string['managesubscriptions'] = 'Manage subscriptions'; $string['managerules'] = 'Manage rules'; +$string['messageheader'] = 'Customize your notification message'; +$string['messagetemplate'] = 'Message template'; +$string['messagetemplate_help'] = 'This is the content of the message that will be sent to users, when the given conditions of the rule are met. You are allowed to use following templates in this. +
{link} - Link to the location where the event happened. +
{modulelink} - Link to the module where the event has happened. +
{rulename} - Name of this rule. +
{description} - Rule description. +
{eventname} - Name of the event associated with the rule.'; +$string['minutes'] = 'in minutes:'; +$string['name'] = 'Name of the rule: '; +$string['name_help'] = "Choose a name for the rule."; +$string['norules'] = 'There are no rules you can subscribe to.'; +$string['manageruleslink'] = 'You can manage rules from {$a} page.'; $string['pluginname'] = 'Event monitor'; +$string['processevents'] = 'Process events'; $string['selectcourse'] = 'Visit this report at course level to get a list of possible modules'; +$string['selectevent'] = 'Select an event:'; +$string['selectevent_help'] = "Select an event to monitor."; +$string['selectfrequency'] = 'Frequency of events:'; +$string['selectfrequency_help'] = "Frequency defines the denisty of the event occurance. Select criterias to define how frequently the event should happen to trigger the notification."; +$string['selectminutes'] = 'in minutes:'; +$string['selectplugin'] = 'Select the plugin type:'; +$string['selectplugin_help'] = "Select a plugin that you are interested in monitoring."; +$string['title'] = '{$a->coursename} : {$a->reportname}'; $string['tool/monitor:managerules'] = 'Manage event monitor rules'; $string['tool/monitor:subscribe'] = 'Subscribe to event monitor rules'; + diff --git a/admin/tool/monitor/managerules.php b/admin/tool/monitor/managerules.php new file mode 100644 index 00000000000..e69de29bb2d From 371d5e0b66c95cd70473e7d68bdadcda936ae4dd Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Tue, 15 Jul 2014 14:05:42 +0800 Subject: [PATCH 13/44] MDL-45758 tool_monitor: Create rendering code for manage rules page Original issue - MDL-46110 --- .../classes/output/managerules/renderable.php | 199 ++++++++++++++++++ .../classes/output/managerules/renderer.php | 84 ++++++++ admin/tool/monitor/lang/en/tool_monitor.php | 1 + 3 files changed, 284 insertions(+) create mode 100644 admin/tool/monitor/classes/output/managerules/renderable.php create mode 100644 admin/tool/monitor/classes/output/managerules/renderer.php diff --git a/admin/tool/monitor/classes/output/managerules/renderable.php b/admin/tool/monitor/classes/output/managerules/renderable.php new file mode 100644 index 00000000000..68e8337b531 --- /dev/null +++ b/admin/tool/monitor/classes/output/managerules/renderable.php @@ -0,0 +1,199 @@ +. + +/** + * Renderable class for manage rules page. + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace tool_monitor\output\managerules; + +defined('MOODLE_INTERNAL') || die; + +require_once($CFG->libdir . '/tablelib.php'); + +/** + * Renderable class for manage rules page. + * + * @since Moodle 2.8 + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class renderable extends \table_sql implements \renderable { + + /** + * @var int course id. + */ + public $courseid; + + /** + * @var \context_course|\context_system context of the page to be rendered. + */ + protected $context; + + /** + * @var bool Does the user have capability to manage rules at site context. + */ + protected $hassystemcap; + + /** + * Sets up the table_log parameters. + * + * @param string $uniqueid unique id of form. + * @param \moodle_url $url url where this table is displayed. + * @param int $courseid course id. + * @param int $perpage Number of rules to display per page. + */ + public function __construct($uniqueid, \moodle_url $url, $courseid = 0, $perpage = 100) { + parent::__construct($uniqueid); + + $this->set_attribute('class', 'toolmonitor managerules generaltable generalbox'); + $this->define_columns(array('name', 'description', 'plugin', 'eventname', 'filters', 'manage')); + $this->define_headers(array( + get_string('name'), + get_string('description'), + get_string('plugin'), + get_string('eventname'), + get_string('frequency', 'tool_monitor'), + get_string('manage', 'tool_monitor'), + ) + ); + $this->courseid = $courseid; + $this->pagesize = $perpage; + $systemcontext = \context_system::instance(); + $this->context = empty($courseid) ? $systemcontext : \context_course::instance($courseid); + $this->hassystemcap = has_capability('tool/monitor:managerules', $systemcontext); + $this->collapsible(false); + $this->sortable(false); + $this->pageable(true); + $this->is_downloadable(false); + $this->define_baseurl($url); + } + + /** + * Generate content for name column. + * + * @param \tool_monitor\rule $rule rule object + * + * @return string html used to display the column field. + */ + public function col_name(\tool_monitor\rule $rule) { + return $rule->get_name($this->context); + } + + /** + * Generate content for description column. + * + * @param \tool_monitor\rule $rule rule object + * + * @return string html used to display the column field. + */ + public function col_description(\tool_monitor\rule $rule) { + return $rule->get_description($this->context); + } + + /** + * Generate content for plugin column. + * + * @param \tool_monitor\rule $rule rule object + * + * @return string html used to display the column field. + */ + public function col_plugin(\tool_monitor\rule $rule) { + return $rule->get_plugin_name(); + } + + /** + * Generate content for eventname column. + * + * @param \tool_monitor\rule $rule rule object + * + * @return string html used to display the column field. + */ + public function col_eventname(\tool_monitor\rule $rule) { + return $rule->get_event_name(); + } + + /** + * Generate content for filters column. + * + * @param \tool_monitor\rule $rule rule object + * + * @return string html used to display the filters column field. + */ + public function col_filters(\tool_monitor\rule $rule) { + return $rule->get_filters_description(); + } + + /** + * Generate content for manage column. + * + * @param \tool_monitor\rule $rule rule object + * + * @return string html used to display the manage column field. + */ + public function col_manage(\tool_monitor\rule $rule) { + global $OUTPUT, $CFG; + $manage = ''; + // We don't need to check for capability at course level since, user is never shown this page, + // if he doesn't have the capability. + if ($this->hassystemcap || ($rule->courseid !== 0)) { + // There might be site rules which the user can not manage. + $editurl = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/edit.php', array('ruleid' => $rule->id, + 'courseid' => $rule->courseid)); + $copyurl = new \moodle_url($CFG->wwwroot. '/report/monitor/managerules.php', + array('ruleid' => $rule->id, 'copy' => 1, 'courseid' => $this->courseid)); + $deleteurl = new \moodle_url($CFG->wwwroot. '/report/monitor/delete.php', array('ruleid' => $rule->id)); + + $icon = $OUTPUT->render(new \pix_icon('t/edit', '')); + $manage .= \html_writer::link($editurl, $icon, array('class' => 'action-icon')); + + $icon = $OUTPUT->render(new \pix_icon('t/copy', '')); + $manage .= \html_writer::link($copyurl, $icon, array('class' => 'action-icon')); + + $icon = $OUTPUT->render(new \pix_icon('t/delete', '')); + $manage .= \html_writer::link($deleteurl, $icon, array('class' => 'action-icon')); + } else { + $manage = '-'; + } + return $manage; + } + + /** + * Query the reader. Store results in the object for use by build_table. + * + * @param int $pagesize size of page for paginated displayed table. + * @param bool $useinitialsbar do you want to use the initials bar. + */ + public function query_db($pagesize, $useinitialsbar = true) { + + $total = \tool_monitor\rule_manager::count_rules_by_courseid($this->courseid); + $this->pagesize($pagesize, $total); + $rules = \tool_monitor\rule_manager::get_rules_by_courseid($this->courseid, $this->get_page_start(), + $this->get_page_size()); + foreach ($rules as $rule) { + $this->rawdata[] = \tool_monitor\rule_manager::get_rule($rule); + } + // Set initial bars. + if ($useinitialsbar) { + $this->initialbars($total > $pagesize); + } + } +} diff --git a/admin/tool/monitor/classes/output/managerules/renderer.php b/admin/tool/monitor/classes/output/managerules/renderer.php new file mode 100644 index 00000000000..889817da227 --- /dev/null +++ b/admin/tool/monitor/classes/output/managerules/renderer.php @@ -0,0 +1,84 @@ +. + +/** + * Renderer class for manage rules page. + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace tool_monitor\output\managerules; + +defined('MOODLE_INTERNAL') || die; + +/** + * Renderer class for manage rules page. + * + * @since Moodle 2.8 + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class renderer extends \plugin_renderer_base { + + /** + * Get html to display on the page. + * + * @param renderable $renderable renderable widget + * + * @return string to display on the mangerules page. + */ + protected function render_renderable(renderable $renderable) { + $o = $this->render_table($renderable); + $o .= $this->render_add_button($renderable->courseid); + + return $o; + } + + /** + * Get html to display on the page. + * + * @param renderable $renderable renderable widget + * + * @return string to display on the mangerules page. + */ + protected function render_table(renderable $renderable) { + $o = ''; + ob_start(); + $renderable->out($renderable->pagesize, true); + $o = ob_get_contents(); + ob_end_clean(); + + return $o; + } + + /** + * Html to add a button for adding a new rul. + * + * @param int $courseid course id. + * + * @return string html for the button. + */ + protected function render_add_button($courseid) { + global $CFG; + + $button = \html_writer::tag('button', get_string('addrule', 'tool_monitor')); + $addurl = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/edit.php', array('courseid' => $courseid)); + return \html_writer::link($addurl, $button); + } +} diff --git a/admin/tool/monitor/lang/en/tool_monitor.php b/admin/tool/monitor/lang/en/tool_monitor.php index 9b1e7e55221..13591962bf8 100644 --- a/admin/tool/monitor/lang/en/tool_monitor.php +++ b/admin/tool/monitor/lang/en/tool_monitor.php @@ -24,6 +24,7 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +$string['addrule'] = 'Add a new rule'; $string['allevents'] = 'All events'; $string['allmodules'] = 'All modules'; $string['core'] = 'Core'; From 22f42316311ef9284c014c24c18ff30565cdebf1 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Tue, 15 Jul 2014 14:06:19 +0800 Subject: [PATCH 14/44] MDL-45758 tool_monitor: Display a rule managment interface Original issue - MDL-46110 --- admin/tool/monitor/lang/en/tool_monitor.php | 2 + admin/tool/monitor/managerules.php | 67 +++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/admin/tool/monitor/lang/en/tool_monitor.php b/admin/tool/monitor/lang/en/tool_monitor.php index 13591962bf8..b8a78d578dd 100644 --- a/admin/tool/monitor/lang/en/tool_monitor.php +++ b/admin/tool/monitor/lang/en/tool_monitor.php @@ -35,7 +35,9 @@ $string['description_help'] = "Description is displayed to users when they want $string['defaultmessagetpl'] = 'Rule "{rulename}" has happened. You can find further details at {link}'; $string['eventnotfound'] = 'Event not found'; $string['errorincorrectevent'] = 'Please select an event related to the selected plugin'; +$string['frequency'] = 'Frequency'; $string['freqdesc'] = '{$a->freq} times in {$a->mins} minutes'; +$string['manage'] = 'Manage'; $string['managesubscriptions'] = 'Manage subscriptions'; $string['managerules'] = 'Manage rules'; $string['messageheader'] = 'Customize your notification message'; diff --git a/admin/tool/monitor/managerules.php b/admin/tool/monitor/managerules.php index e69de29bb2d..a40006b0117 100644 --- a/admin/tool/monitor/managerules.php +++ b/admin/tool/monitor/managerules.php @@ -0,0 +1,67 @@ +. + +/** + * This page lets users to manage rules for a given course. + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once(__DIR__ . '/../../../config.php'); +require_once($CFG->libdir.'/adminlib.php'); + +$courseid = optional_param('courseid', 0, PARAM_INT); + +// Validate course id. +if (empty($courseid)) { + require_login(); + $context = context_system::instance(); + $coursename = format_string($SITE->fullname, true, array('context' => $context)); + $PAGE->set_context($context); +} else { + $course = get_course($courseid); + require_login($course); + $context = context_course::instance($course->id); + $coursename = format_string($course->fullname, true, array('context' => $context)); +} + +// Check for caps. +require_capability('tool/monitor:managerules', $context); + +// Set up the page. +$a = new stdClass(); +$a->coursename = $coursename; +$a->reportname = get_string('pluginname', 'tool_monitor'); +$title = get_string('title', 'tool_monitor', $a); +$manageurl = new moodle_url("/admin/tool/monitor/managerules.php", array('courseid' => $courseid)); + +$PAGE->set_url($manageurl); +$PAGE->set_pagelayout('report'); +$PAGE->set_title($title); +$PAGE->set_heading($title); + +// Site level report. +if (empty($courseid)) { + admin_externalpage_setup('toolmonitorrules', '', null, '', array('pagelayout' => 'report')); +} + +echo $OUTPUT->header(); +$renderable = new \tool_monitor\output\managerules\renderable('toolmonitorrules', $manageurl, $courseid); +$renderer = $PAGE->get_renderer('tool_monitor', 'managerules'); +echo $renderer->render($renderable); +echo $OUTPUT->footer(); From 3870ad7a2f9a8f5c308f4fda270639f1d8ffd071 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Wed, 16 Jul 2014 10:23:24 +0800 Subject: [PATCH 15/44] MDL-45758 tool_monitor: Handle rule managment Original issue - MDL-46130 --- .../classes/output/managerules/renderable.php | 14 +++++++---- admin/tool/monitor/lang/en/tool_monitor.php | 4 +++ admin/tool/monitor/managerules.php | 25 +++++++++++++++++++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/admin/tool/monitor/classes/output/managerules/renderable.php b/admin/tool/monitor/classes/output/managerules/renderable.php index 68e8337b531..dabf3255b34 100644 --- a/admin/tool/monitor/classes/output/managerules/renderable.php +++ b/admin/tool/monitor/classes/output/managerules/renderable.php @@ -158,9 +158,10 @@ class renderable extends \table_sql implements \renderable { // There might be site rules which the user can not manage. $editurl = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/edit.php', array('ruleid' => $rule->id, 'courseid' => $rule->courseid)); - $copyurl = new \moodle_url($CFG->wwwroot. '/report/monitor/managerules.php', - array('ruleid' => $rule->id, 'copy' => 1, 'courseid' => $this->courseid)); - $deleteurl = new \moodle_url($CFG->wwwroot. '/report/monitor/delete.php', array('ruleid' => $rule->id)); + $copyurl = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/managerules.php', + array('ruleid' => $rule->id, 'action' => 'copy', 'courseid' => $this->courseid)); + $deleteurl = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/managerules.php', array('ruleid' => $rule->id, + 'action' => 'delete', 'courseid' => $rule->courseid)); $icon = $OUTPUT->render(new \pix_icon('t/edit', '')); $manage .= \html_writer::link($editurl, $icon, array('class' => 'action-icon')); @@ -168,8 +169,11 @@ class renderable extends \table_sql implements \renderable { $icon = $OUTPUT->render(new \pix_icon('t/copy', '')); $manage .= \html_writer::link($copyurl, $icon, array('class' => 'action-icon')); - $icon = $OUTPUT->render(new \pix_icon('t/delete', '')); - $manage .= \html_writer::link($deleteurl, $icon, array('class' => 'action-icon')); + $a = $rule->get_name($this->context); + $action = new \component_action('click', 'M.util.show_confirm_dialog', array('message' => get_string('ruleareyousure', + 'tool_monitor', $a))); + $icon = $OUTPUT->action_link($deleteurl, new \pix_icon('t/delete', ''), $action); + $manage .= $icon; } else { $manage = '-'; } diff --git a/admin/tool/monitor/lang/en/tool_monitor.php b/admin/tool/monitor/lang/en/tool_monitor.php index b8a78d578dd..8355cd0731b 100644 --- a/admin/tool/monitor/lang/en/tool_monitor.php +++ b/admin/tool/monitor/lang/en/tool_monitor.php @@ -55,6 +55,10 @@ $string['norules'] = 'There are no rules you can subscribe to.'; $string['manageruleslink'] = 'You can manage rules from {$a} page.'; $string['pluginname'] = 'Event monitor'; $string['processevents'] = 'Process events'; +$string['ruleareyousure'] = 'Are you sure you want to delete rule "{$a}"?'; +$string['rulecopysuccess'] = 'Rule successfully copied'; +$string['ruledeletesuccess'] = 'Rule successfully deleted'; +$string['rulenopermissions'] = 'You do not have permissions to "{$a} a rule"'; $string['selectcourse'] = 'Visit this report at course level to get a list of possible modules'; $string['selectevent'] = 'Select an event:'; $string['selectevent_help'] = "Select an event to monitor."; diff --git a/admin/tool/monitor/managerules.php b/admin/tool/monitor/managerules.php index a40006b0117..ec1065919dc 100644 --- a/admin/tool/monitor/managerules.php +++ b/admin/tool/monitor/managerules.php @@ -26,6 +26,8 @@ require_once(__DIR__ . '/../../../config.php'); require_once($CFG->libdir.'/adminlib.php'); $courseid = optional_param('courseid', 0, PARAM_INT); +$ruleid = optional_param('ruleid', 0, PARAM_INT); +$action = optional_param('action', '', PARAM_ALPHA); // Validate course id. if (empty($courseid)) { @@ -61,6 +63,29 @@ if (empty($courseid)) { } echo $OUTPUT->header(); + +// Copy/delete rule if needed. +if (!empty($action) && $ruleid) { + $rule = \tool_monitor\rule_manager::get_rule($ruleid); + if ($rule->can_manage_rule()) { + switch ($action) { + case 'copy' : + $rule->duplicate_rule($courseid); + echo $OUTPUT->notification(get_string('rulecopysuccess', 'tool_monitor'), 'notifysuccess'); + break; + case 'delete' : + $rule->delete_rule(); + echo $OUTPUT->notification(get_string('ruledeletesuccess', 'tool_monitor'), 'notifysuccess'); + break; + default: + } + } else { + // User doesn't have permissions. Should never happen for real users. + throw new moodle_exception('rulenopermissions', 'tool_monitor', $manageurl, $action); + } +} + +// Render the rule list. $renderable = new \tool_monitor\output\managerules\renderable('toolmonitorrules', $manageurl, $courseid); $renderer = $PAGE->get_renderer('tool_monitor', 'managerules'); echo $renderer->render($renderable); From 3432c96d3a8289fd6205200172e56f5e9fdad57e Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Thu, 17 Jul 2014 17:37:26 +0800 Subject: [PATCH 16/44] MDL-45758 tool_monitor: Create a subscription instance class Original issue - MDL-46241 --- admin/tool/monitor/classes/subscription.php | 96 +++++++++++++++++++++ admin/tool/monitor/lang/en/tool_monitor.php | 2 +- 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 admin/tool/monitor/classes/subscription.php diff --git a/admin/tool/monitor/classes/subscription.php b/admin/tool/monitor/classes/subscription.php new file mode 100644 index 00000000000..4355e8c2d22 --- /dev/null +++ b/admin/tool/monitor/classes/subscription.php @@ -0,0 +1,96 @@ +. + +/** + * Class represents a single subscription. + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace tool_monitor; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Class represents a single subscription instance (i.e with all the subscription info). + * + * @since Moodle 2.8 + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class subscription { + use helper_trait; + /** + * @var \stdClass + */ + protected $subscription; + + /** + * Constructor. + * + * use {@link \tool_monitor\subscription_manager::get_subscription} to get an instance instead of directly calling this method. + * + * @param \stdClass $subscription + */ + public function __construct($subscription) { + $this->subscription = $subscription; + } + + /** + * Magic get method. + * + * @param string $prop property to get. + * + * @return mixed + * @throws \coding_exception + */ + public function __get($prop) { + if (property_exists($this->subscription, $prop)) { + return $this->subscription->$prop; + } + throw new \coding_exception('Property "' . $prop . '" doesn\'t exist'); + } + + /** + * Get a human readable name for instances associated with this subscription. + * + * @return string + * @throws \coding_exception + */ + public function get_instance_name() { + if ($this->plugin === 'core') { + $string = get_string('allevents', 'tool_monitor'); + } else { + if ($this->cmid == 0) { + $string = get_string('allmodules', 'tool_monitor'); + } else { + $cms = get_fast_modinfo($this->courseid); + $cms = $cms->get_cms(); + if (isset($cms[$this->cmid])) { + $string = $cms[$this->cmid]->get_formatted_name(); // Instance name. + } else { + // Something is wrong, instance is not present anymore. + $string = get_string('invalidmodule', 'tool_monitor'); + } + } + } + + return $string; + } +} diff --git a/admin/tool/monitor/lang/en/tool_monitor.php b/admin/tool/monitor/lang/en/tool_monitor.php index 8355cd0731b..f9ff73e4712 100644 --- a/admin/tool/monitor/lang/en/tool_monitor.php +++ b/admin/tool/monitor/lang/en/tool_monitor.php @@ -36,7 +36,7 @@ $string['defaultmessagetpl'] = 'Rule "{rulename}" has happened. You can find fur $string['eventnotfound'] = 'Event not found'; $string['errorincorrectevent'] = 'Please select an event related to the selected plugin'; $string['frequency'] = 'Frequency'; -$string['freqdesc'] = '{$a->freq} times in {$a->mins} minutes'; +$string['invalidmodule'] = 'Invalid module'; $string['manage'] = 'Manage'; $string['managesubscriptions'] = 'Manage subscriptions'; $string['managerules'] = 'Manage rules'; From 76b7ce41abecac17636cd89bb76f11d4aa220bf8 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Tue, 9 Sep 2014 09:50:18 +0530 Subject: [PATCH 17/44] MDL-45758 tool_monitor: Add a renderer for the subscription page Original issue - MDL-46111 --- .../classes/output/managesubs/renderer.php | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 admin/tool/monitor/classes/output/managesubs/renderer.php diff --git a/admin/tool/monitor/classes/output/managesubs/renderer.php b/admin/tool/monitor/classes/output/managesubs/renderer.php new file mode 100644 index 00000000000..7d0161f258f --- /dev/null +++ b/admin/tool/monitor/classes/output/managesubs/renderer.php @@ -0,0 +1,79 @@ +. + +/** + * Renderer class for manage subscriptions page. + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace tool_monitor\output\managesubs; + +defined('MOODLE_INTERNAL') || die; + +/** + * Renderer class for manage subscriptions page. + * + * @since Moodle 2.8 + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class renderer extends \plugin_renderer_base { + + /** + * Get html to display on the page. + * + * @param subs $renderable renderable widget + * + * @return string to display on the mangesubs page. + */ + protected function render_subs(subs $renderable) { + $o = $this->render_table($renderable); + return $o; + } + + /** + * Get html to display on the page. + * + * @param rules $renderable renderable widget + * + * @return string to display on the mangesubs page. + */ + protected function render_rules(rules $renderable) { + $o = $this->render_table($renderable); + return $o; + } + + /** + * Get html to display on the page. + * + * @param rules|subs $renderable renderable widget + * + * @return string to display on the mangesubs page. + */ + protected function render_table($renderable) { + $o = ''; + ob_start(); + $renderable->out($renderable->pagesize, true); + $o = ob_get_contents(); + ob_end_clean(); + + return $o; + } +} From 58dcafb05a16532d95dc7edbe655f575629f8d39 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Tue, 9 Sep 2014 09:50:36 +0530 Subject: [PATCH 18/44] MDL-45758 tool_monitor: Add renderables for the subscription page Original issue - MDL-46111 --- .../classes/output/managesubs/rules.php | 136 +++++++++++++++++ .../classes/output/managesubs/subs.php | 142 ++++++++++++++++++ 2 files changed, 278 insertions(+) create mode 100644 admin/tool/monitor/classes/output/managesubs/rules.php create mode 100644 admin/tool/monitor/classes/output/managesubs/subs.php diff --git a/admin/tool/monitor/classes/output/managesubs/rules.php b/admin/tool/monitor/classes/output/managesubs/rules.php new file mode 100644 index 00000000000..a336b6ba8bf --- /dev/null +++ b/admin/tool/monitor/classes/output/managesubs/rules.php @@ -0,0 +1,136 @@ +. + +/** + * Renderable class to display a set of rules in the manage subscriptions page. + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace tool_monitor\output\managesubs; + +defined('MOODLE_INTERNAL') || die; + +require_once($CFG->libdir . '/tablelib.php'); + +/** + * Renderable class to display a set of rules in the manage subscriptions page. + * + * @since Moodle 2.8 + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class rules extends \table_sql implements \renderable { + + /** + * @var int course id. + */ + public $courseid; + + /** + * @var \context_course|\context_system context of the page to be rendered. + */ + protected $context; + + /** + * Sets up the table_log parameters. + * + * @param string $uniqueid unique id of form. + * @param \moodle_url $url url where this table is displayed. + * @param int $courseid course id. + * @param int $perpage Number of rules to display per page. + */ + public function __construct($uniqueid, \moodle_url $url, $courseid = 0, $perpage = 100) { + parent::__construct($uniqueid); + + $this->set_attribute('class', 'toolmonitor subscriberules generaltable generalbox'); + $this->define_columns(array('name', 'description', 'select')); + $this->define_headers(array( + get_string('name'), + get_string('description'), + get_string('select') + ) + ); + $this->courseid = $courseid; + $this->pagesize = $perpage; + $systemcontext = \context_system::instance(); + $this->context = empty($courseid) ? $systemcontext : \context_course::instance($courseid); + $this->collapsible(false); + $this->sortable(false); + $this->pageable(true); + $this->is_downloadable(false); + $this->define_baseurl($url); + } + + /** + * Generate content for name column. + * + * @param \tool_monitor\rule $rule rule object + * + * @return string html used to display the column field. + */ + public function col_name(\tool_monitor\rule $rule) { + return $rule->get_name($this->context); + } + + /** + * Generate content for description column. + * + * @param \tool_monitor\rule $rule rule object + * + * @return string html used to display the column field. + */ + public function col_description(\tool_monitor\rule $rule) { + return $rule->get_description($this->context); + } + + /** + * Generate content for plugin column. + * + * @param \tool_monitor\rule $rule rule object + * + * @return string html used to display the column field. + */ + public function col_select(\tool_monitor\rule $rule) { + global $OUTPUT; + $select = $rule->get_module_select($this->courseid); + return is_object($select) ? $OUTPUT->render($select) : $select; + } + + /** + * Query the reader. Store results in the object for use by build_table. + * + * @param int $pagesize size of page for paginated displayed table. + * @param bool $useinitialsbar do you want to use the initials bar. + */ + public function query_db($pagesize, $useinitialsbar = true) { + + $total = \tool_monitor\rule_manager::count_rules_by_courseid($this->courseid); + $this->pagesize($pagesize, $total); + $rules = \tool_monitor\rule_manager::get_rules_by_courseid($this->courseid, $this->get_page_start(), + $this->get_page_size()); + foreach ($rules as $rule) { + $this->rawdata[] = \tool_monitor\rule_manager::get_rule($rule); + } + // Set initial bars. + if ($useinitialsbar) { + $this->initialbars($total > $pagesize); + } + } +} diff --git a/admin/tool/monitor/classes/output/managesubs/subs.php b/admin/tool/monitor/classes/output/managesubs/subs.php new file mode 100644 index 00000000000..1195894724d --- /dev/null +++ b/admin/tool/monitor/classes/output/managesubs/subs.php @@ -0,0 +1,142 @@ +. + +/** + * Renderable class to display a set of subscriptions in the manage subscriptions page. + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace tool_monitor\output\managesubs; + +defined('MOODLE_INTERNAL') || die; + +require_once($CFG->libdir . '/tablelib.php'); + +/** + * Renderable class to display a set of subscriptions in the manage subscriptions page. + * + * @since Moodle 2.8 + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class subs extends \table_sql implements \renderable { + + /** + * @var int course id. + */ + public $courseid; + + /** + * @var \context_course|\context_system context of the page to be rendered. + */ + protected $context; + + /** + * Sets up the table_log parameters. + * + * @param string $uniqueid unique id of form. + * @param \moodle_url $url url where this table is displayed. + * @param int $courseid course id. + * @param int $perpage Number of rules to display per page. + */ + public function __construct($uniqueid, \moodle_url $url, $courseid = 0, $perpage = 100) { + parent::__construct($uniqueid); + + $this->set_attribute('class', 'toolmonitor subscriptions generaltable generalbox'); + $this->define_columns(array('name', 'instance', 'unsubscribe')); + $this->define_headers(array( + get_string('name'), + get_string('moduleinstance', 'tool_monitor'), + get_string('unsubscribe', 'tool_monitor') + ) + ); + $this->courseid = $courseid; + $this->pagesize = $perpage; + $systemcontext = \context_system::instance(); + $this->context = empty($courseid) ? $systemcontext : \context_course::instance($courseid); + $this->collapsible(false); + $this->sortable(false); + $this->pageable(true); + $this->is_downloadable(false); + $this->define_baseurl($url); + } + + /** + * Generate content for name column. + * + * @param \tool_monitor\subscription $sub subscription object + * + * @return string html used to display the column field. + */ + public function col_name(\tool_monitor\subscription $sub) { + return $sub->get_name($this->context); + } + + /** + * Generate content for description column. + * + * @param \tool_monitor\subscription $sub subscription object + * + * @return string html used to display the column field. + */ + public function col_instance(\tool_monitor\subscription $sub) { + return $sub->get_instance_name(); + } + + /** + * Generate content for manage column. + * + * @param \tool_monitor\subscription $sub subscription object + * + * @return string html used to display the column field. + */ + public function col_unsubscribe(\tool_monitor\subscription $sub) { + global $OUTPUT, $CFG; + + $a = $sub->get_name($this->context); + $deleteurl = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/index.php', array('subscriptionid' => $sub->id, + 'action' => 'unsubscribe', 'courseid' => $this->courseid)); + $action = new \component_action('click', 'M.util.show_confirm_dialog', array('message' => get_string('subareyousure', + 'tool_monitor', $a))); + $icon = $OUTPUT->action_link($deleteurl, new \pix_icon('t/delete', ''), $action); + return $icon; + } + + /** + * Query the reader. Store results in the object for use by build_table. + * + * @param int $pagesize size of page for paginated displayed table. + * @param bool $useinitialsbar do you want to use the initials bar. + */ + public function query_db($pagesize, $useinitialsbar = true) { + + $total = \tool_monitor\subscription_manager::count_user_subscriptions_for_course($this->courseid); + $this->pagesize($pagesize, $total); + $subs = \tool_monitor\subscription_manager::get_user_subscriptions_for_course($this->courseid, $this->get_page_start(), + $this->get_page_size()); + foreach ($subs as $subscription) { + $this->rawdata[] = \tool_monitor\subscription_manager::get_subscription($subscription->id); + } + // Set initial bars. + if ($useinitialsbar) { + $this->initialbars($total > $pagesize); + } + } +} From ac0e4dad7f15d29538f22747bfd38d40807d5472 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Tue, 9 Sep 2014 09:51:37 +0530 Subject: [PATCH 19/44] MDL-45758 tool_monitor: Update subscription manager class Update the class to support the subs renderable Original issue - MDL-461111 --- .../monitor/classes/subscription_manager.php | 44 ++++++++++++++++--- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/admin/tool/monitor/classes/subscription_manager.php b/admin/tool/monitor/classes/subscription_manager.php index f5665ffff8f..5c3e5efeb67 100644 --- a/admin/tool/monitor/classes/subscription_manager.php +++ b/admin/tool/monitor/classes/subscription_manager.php @@ -73,7 +73,7 @@ class subscription_manager { */ public static function delete_subscription($subscriptionorid, $checkuser = true) { global $DB, $USER; - if (get_class($subscriptionorid) === 'tool_monitor\subscription') { + if (is_object($subscriptionorid)) { $subscription = $subscriptionorid; } else { $subscription = self::get_subscription($subscriptionorid); @@ -120,22 +120,45 @@ class subscription_manager { * Get an array of subscriptions for a given user in a given course. * * @param int $courseid course id. + * @param int $limitfrom Limit from which to fetch rules. + * @param int $limitto Limit to which rules need to be fetched. * @param int $userid Id of the user for which the subscription needs to be fetched. Defaults to $USER; * @param string $order Order to sort the subscriptions. * * @return array list of subscriptions */ - public static function get_user_subscriptions_for_course($courseid, $userid = 0, $order = 's.timecreated DESC') { + public static function get_user_subscriptions_for_course($courseid, $limitfrom = 0, $limitto = 0, $userid = 0, + $order = 's.timecreated DESC' ) { global $DB, $USER; if ($userid == 0) { $userid = $USER->id; } $sql = self::get_subscription_join_rule_sql(); - $sql .= "WHERE s.courseid = :courseid AND s.userid = :userid $order"; + $sql .= "WHERE s.courseid = :courseid AND s.userid = :userid ORDER BY $order"; - return $DB->get_records_sql($sql, array('courseid' => $courseid, 'userid' => $userid)); + return $DB->get_records_sql($sql, array('courseid' => $courseid, 'userid' => $userid), $limitfrom, $limitto); } + /** + * Get count of subscriptions for a given user in a given course. + * + * @param int $courseid course id. + * @param int $userid Id of the user for which the subscription needs to be fetched. Defaults to $USER; + * + * @return array list of subscriptions + */ + public static function count_user_subscriptions_for_course($courseid, $userid = 0) { + global $DB, $USER; + if ($userid == 0) { + $userid = $USER->id; + } + $sql = self::get_subscription_join_rule_sql(true); + $sql .= "WHERE s.courseid = :courseid AND s.userid = :userid"; + + return $DB->count_records_sql($sql, array('courseid' => $courseid, 'userid' => $userid)); + } + + /** * Return a list of subscriptions for a given event. * @@ -160,11 +183,18 @@ class subscription_manager { /** * Return sql to join rule and subscription table. * + * @param bool $count Weather if this is a count query or not. + * * @return string the sql. */ - public static function get_subscription_join_rule_sql() { - $sql = "SELECT s.*, r.description, r.name, r.userid as ruleuserid, r.courseid as rulecourseid, r.plugin, - r.eventname, r.message_template, r.frequency, r.timewindow + public static function get_subscription_join_rule_sql($count = false) { + if ($count) { + $select = "SELECT COUNT(s.id) "; + } else { + $select = "SELECT s.*, r.description, r.descriptionformat, r.name, r.userid as ruleuserid, r.courseid as rulecourseid, + r.plugin, r.eventname, r.template, r.templateformat, r.frequency, r.timewindow"; + } + $sql = $select . " FROM {tool_monitor_rules} r JOIN {tool_monitor_subscriptions} s ON r.id = s.ruleid "; From 044503e33df2100ecf81010da7999f60fd43dd4d Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Tue, 9 Sep 2014 09:52:51 +0530 Subject: [PATCH 20/44] MDL-45758 tool_monitor: Add a UI page to manage subscriptions Original issue - MDL-46111 --- admin/tool/monitor/index.php | 110 ++++++++++++++++++++ admin/tool/monitor/lang/en/tool_monitor.php | 12 ++- 2 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 admin/tool/monitor/index.php diff --git a/admin/tool/monitor/index.php b/admin/tool/monitor/index.php new file mode 100644 index 00000000000..d2a90a57d8b --- /dev/null +++ b/admin/tool/monitor/index.php @@ -0,0 +1,110 @@ +. + +/** + * This page lets users to manage rules for a given course. + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once(__DIR__ . '/../../../config.php'); +require_once($CFG->libdir.'/adminlib.php'); + +$courseid = optional_param('courseid', 0, PARAM_INT); +$action = optional_param('action', '', PARAM_ALPHA); +$cmid = optional_param('cmid', 0, PARAM_INT); +$ruleid = optional_param('ruleid', 0, PARAM_INT); +$subscriptionid = optional_param('subscriptionid', 0, PARAM_INT); + +// Validate course id. +if (empty($courseid)) { + require_login(); + $context = context_system::instance(); + $coursename = format_string($SITE->fullname, true, array('context' => $context)); + $PAGE->set_context($context); +} else { + $course = get_course($courseid); + require_login($course); + $context = context_course::instance($course->id); + $coursename = format_string($course->fullname, true, array('context' => $context)); +} + +// Check for caps. +require_capability('tool/monitor:subscribe', $context); + +// Set up the page. +$a = new stdClass(); +$a->coursename = $coursename; +$a->reportname = get_string('pluginname', 'tool_monitor'); +$title = get_string('title', 'tool_monitor', $a); +$indexurl = new moodle_url("/admin/tool/monitor/index.php", array('courseid' => $courseid)); + +$PAGE->set_url($indexurl); +$PAGE->set_pagelayout('report'); +$PAGE->set_title($title); +$PAGE->set_heading($title); + +// Site level report. +if (empty($courseid)) { + admin_externalpage_setup('toolmonitorsubscriptions', '', null, '', array('pagelayout' => 'report')); +} + +echo $OUTPUT->header(); + +// Create/delete subscription if needed. +if (!empty($action)) { + switch ($action) { + case 'subscribe' : + $rule = \tool_monitor\rule_manager::get_rule($ruleid); + $rule->subscribe_user($courseid, $cmid); + echo $OUTPUT->notification(get_string('subcreatesuccess', 'tool_monitor'), 'notifysuccess'); + break; + case 'unsubscribe' : + \tool_monitor\subscription_manager::delete_subscription($subscriptionid); + echo $OUTPUT->notification(get_string('subdeletesuccess', 'tool_monitor'), 'notifysuccess'); + break; + default: + } +} + +// Render the current subscriptions list. +$totalsubs = \tool_monitor\subscription_manager::count_user_subscriptions_for_course($courseid); +$renderer = $PAGE->get_renderer('tool_monitor', 'managesubs'); +if (!empty($totalsubs)) { + // Show the subscriptions section only if there are subscriptions. + $subs = new \tool_monitor\output\managesubs\subs('toolmonitorsubs', $indexurl, $courseid); + echo $OUTPUT->heading(get_string('currentsubscriptions', 'tool_monitor')); + echo $renderer->render($subs); +} + +// Render the potential rules list. +$totalrules = \tool_monitor\rule_manager::count_rules_by_courseid($courseid); +echo $OUTPUT->heading(get_string('rulescansubscribe', 'tool_monitor')); +if (!empty($totalrules)) { + $rules = new \tool_monitor\output\managesubs\rules('toolmonitorrules', $indexurl, $courseid); + echo $renderer->render($rules); +} else { + // No rules present. Show a link to manage rules page if permissions permit. + echo html_writer::tag('span', get_string('norules', 'tool_monitor')); + if (has_capability('tool/monitor:managerules', $context)) { + $manageurl = new moodle_url("/admin/tool/monitor/managerules.php", array('courseid' => $courseid)); + $a = html_writer::link($manageurl, get_string('managerules', 'tool_monitor')); + echo html_writer::tag('span', get_string('manageruleslink', 'tool_monitor', $a)); + } +} +echo $OUTPUT->footer(); diff --git a/admin/tool/monitor/lang/en/tool_monitor.php b/admin/tool/monitor/lang/en/tool_monitor.php index f9ff73e4712..e7e510a731a 100644 --- a/admin/tool/monitor/lang/en/tool_monitor.php +++ b/admin/tool/monitor/lang/en/tool_monitor.php @@ -30,13 +30,18 @@ $string['allmodules'] = 'All modules'; $string['core'] = 'Core'; $string['customizefilters'] = 'Select the frequency of the events'; $string['customizemessage'] = 'Cutomize the notification message'; +$string['currentsubscriptions'] = 'Your current subscriptions'; $string['description'] = 'Description:'; $string['description_help'] = "Description is displayed to users when they want to subscribe to this rule. This helps them understand what the rule is about."; $string['defaultmessagetpl'] = 'Rule "{rulename}" has happened. You can find further details at {link}'; $string['eventnotfound'] = 'Event not found'; $string['errorincorrectevent'] = 'Please select an event related to the selected plugin'; +$string['freqdesc'] = '{$a->freq} times in {$a->mins} minutes'; $string['frequency'] = 'Frequency'; $string['invalidmodule'] = 'Invalid module'; +$string['norules'] = 'There are no rules you can subscribe to.'; +$string['manageruleslink'] = 'You can manage rules from {$a} page.'; +$string['moduleinstance'] = 'Module instance'; $string['manage'] = 'Manage'; $string['managesubscriptions'] = 'Manage subscriptions'; $string['managerules'] = 'Manage rules'; @@ -51,14 +56,13 @@ $string['messagetemplate_help'] = 'This is the content of the message that will $string['minutes'] = 'in minutes:'; $string['name'] = 'Name of the rule: '; $string['name_help'] = "Choose a name for the rule."; -$string['norules'] = 'There are no rules you can subscribe to.'; -$string['manageruleslink'] = 'You can manage rules from {$a} page.'; $string['pluginname'] = 'Event monitor'; $string['processevents'] = 'Process events'; $string['ruleareyousure'] = 'Are you sure you want to delete rule "{$a}"?'; $string['rulecopysuccess'] = 'Rule successfully copied'; $string['ruledeletesuccess'] = 'Rule successfully deleted'; $string['rulenopermissions'] = 'You do not have permissions to "{$a} a rule"'; +$string['rulescansubscribe'] = 'Rules you can subscribe to'; $string['selectcourse'] = 'Visit this report at course level to get a list of possible modules'; $string['selectevent'] = 'Select an event:'; $string['selectevent_help'] = "Select an event to monitor."; @@ -67,7 +71,11 @@ $string['selectfrequency_help'] = "Frequency defines the denisty of the event oc $string['selectminutes'] = 'in minutes:'; $string['selectplugin'] = 'Select the plugin type:'; $string['selectplugin_help'] = "Select a plugin that you are interested in monitoring."; +$string['subareyousure'] = 'Are you sure you want to delete this subscription for the rule "{$a}"?'; +$string['subcreatesuccess'] = "Subscription successfully created"; +$string['subdeletesuccess'] = "Subscription successfully removed"; $string['title'] = '{$a->coursename} : {$a->reportname}'; $string['tool/monitor:managerules'] = 'Manage event monitor rules'; $string['tool/monitor:subscribe'] = 'Subscribe to event monitor rules'; +$string['unsubscribe'] = 'Unsubscribe'; From 6a7de0d2439483a3c561c65486f8c3645d798e2d Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Sat, 13 Sep 2014 10:23:28 +0530 Subject: [PATCH 21/44] MDL-45758 tool_monitor: Add a course delete observer Original issue - MDL-46510 --- admin/tool/monitor/classes/eventobservers.php | 52 +++++++++++++++++++ admin/tool/monitor/db/events.php | 31 +++++++++++ 2 files changed, 83 insertions(+) create mode 100644 admin/tool/monitor/classes/eventobservers.php create mode 100644 admin/tool/monitor/db/events.php diff --git a/admin/tool/monitor/classes/eventobservers.php b/admin/tool/monitor/classes/eventobservers.php new file mode 100644 index 00000000000..1a98d732f8c --- /dev/null +++ b/admin/tool/monitor/classes/eventobservers.php @@ -0,0 +1,52 @@ +. + +/** + * Observer class containing methods monitoring various events. + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace tool_monitor; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Observer class containing methods monitoring various events. + * + * @since Moodle 2.8 + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class eventobservers { + + /** + * Course delete event observer. + * This observer monitors course delete event, and when a course is deleted it deletes any rules and subscriptions associated + * with it, so no orphan data is left behind. + * + * @param \core\event\course_deleted $event The course deleted event. + */ + public static function course_deleted(\core\event\course_deleted $event) { + $rules = rule_manager::get_rules_by_courseid($event->courseid); + foreach ($rules as $rule) { + rule_manager::delete_rule($rule->id); + } + } +} diff --git a/admin/tool/monitor/db/events.php b/admin/tool/monitor/db/events.php new file mode 100644 index 00000000000..169131b863f --- /dev/null +++ b/admin/tool/monitor/db/events.php @@ -0,0 +1,31 @@ +. + +/** + * This file definies observers needed by the tool. + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +// List of observers. +$observers = array( + array( + 'eventname' => '\core\event\course_deleted', + 'callback' => '\tool_monitor\eventobservers::course_deleted', + ) +); From e1a6022802efe546b983397ea89ad1b606c521d1 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Sat, 13 Sep 2014 10:24:23 +0530 Subject: [PATCH 22/44] MDL-45758 tool_monitor: Add unit tests for the course deleted observer Original issue - MDL-46510 --- .../monitor/tests/eventobservers_test.php | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 admin/tool/monitor/tests/eventobservers_test.php diff --git a/admin/tool/monitor/tests/eventobservers_test.php b/admin/tool/monitor/tests/eventobservers_test.php new file mode 100644 index 00000000000..c097e5566f0 --- /dev/null +++ b/admin/tool/monitor/tests/eventobservers_test.php @@ -0,0 +1,91 @@ +. + +/** + * Unit tests for event observers. + * + * @package tool_monitor + * @category phpunit + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +class tool_monitor_eventobservers_testcase extends advanced_testcase { + + /** + * Test observer for course delete event. + */ + public function test_course_deleted() { + global $DB; + + $this->setAdminUser(); + $this->resetAfterTest(true); + + $user = $this->getDataGenerator()->create_user(); + $course = $this->getDataGenerator()->create_course(); + $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor'); + + $rule = new stdClass(); + $rule->userid = $user->id; + $rule->courseid = $course->id; + $rule->plugin = 'test'; + + $sub = new stdClass(); + $sub->courseid = $course->id; + $sub->userid = $user->id; + + // Add 10 rules for this course with subscriptions. + for ($i = 0; $i < 10; $i++) { + $createdrule = $monitorgenerator->create_rule($rule); + $sub->ruleid = $createdrule->id; + $monitorgenerator->create_subscription($sub); + } + + // Add 10 random rules for random courses. + for ($i = 0; $i < 10; $i++) { + $rule->courseid = rand(10000000, 50000000); + $createdrule = $monitorgenerator->create_rule($rule); + $sub->courseid = $rule->courseid; + $sub->ruleid = $createdrule->id; + $monitorgenerator->create_subscription($sub); + } + + // Verify data before course delete. + $totalrules = \tool_monitor\rule_manager::get_rules_by_plugin('test'); + $this->assertCount(20, $totalrules); + $courserules = \tool_monitor\rule_manager::get_rules_by_courseid($course->id); + $this->assertCount(10, $courserules); + $totalsubs = $DB->get_records('tool_monitor_subscriptions'); + $this->assertCount(20, $totalsubs); + $coursesubs = \tool_monitor\subscription_manager::get_user_subscriptions_for_course($course->id, 0, 0, $user->id); + $this->assertCount(10, $coursesubs); + + // Let us delete the course now. + delete_course($course->id, false); + + // Verify data after course delete. + $totalrules = \tool_monitor\rule_manager::get_rules_by_plugin('test'); + $this->assertCount(10, $totalrules); + $courserules = \tool_monitor\rule_manager::get_rules_by_courseid($course->id); + $this->assertCount(0, $courserules); // Making sure all rules are deleted. + $totalsubs = $DB->get_records('tool_monitor_subscriptions'); + $this->assertCount(10, $totalsubs); + $coursesubs = \tool_monitor\subscription_manager::get_user_subscriptions_for_course($course->id, 0, 0, $user->id); + $this->assertCount(0, $coursesubs); // Making sure all subscriptions are deleted. + } +} From 5b8aa8f70056f406b491dd30b43d35de3da29df5 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Fri, 19 Sep 2014 19:43:46 -0700 Subject: [PATCH 23/44] MDL-45758 tool_monitor: fixed typo Original issue - MDL-47152 --- admin/tool/monitor/lang/en/tool_monitor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/tool/monitor/lang/en/tool_monitor.php b/admin/tool/monitor/lang/en/tool_monitor.php index e7e510a731a..b1529b57bee 100644 --- a/admin/tool/monitor/lang/en/tool_monitor.php +++ b/admin/tool/monitor/lang/en/tool_monitor.php @@ -67,7 +67,7 @@ $string['selectcourse'] = 'Visit this report at course level to get a list of po $string['selectevent'] = 'Select an event:'; $string['selectevent_help'] = "Select an event to monitor."; $string['selectfrequency'] = 'Frequency of events:'; -$string['selectfrequency_help'] = "Frequency defines the denisty of the event occurance. Select criterias to define how frequently the event should happen to trigger the notification."; +$string['selectfrequency_help'] = "Frequency defines the denisty of the event occurrence. Select criterias to define how frequently the event should happen to trigger the notification."; $string['selectminutes'] = 'in minutes:'; $string['selectplugin'] = 'Select the plugin type:'; $string['selectplugin_help'] = "Select a plugin that you are interested in monitoring."; From 27b6839fe297afd7333fad1bf09618ca026698dd Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Fri, 19 Sep 2014 00:37:35 -0700 Subject: [PATCH 24/44] MDL-45758 core: edited get_formatted_help_string Edited the api to accept string parameters Original issue - MDL-47152 --- lib/upgrade.txt | 2 ++ lib/weblib.php | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/upgrade.txt b/lib/upgrade.txt index 07ad74ea2fc..b1690b06dfd 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -22,6 +22,8 @@ information provided here is intended especially for developers. * Google APIs Client Library (lib/google/) has been upgraded to 1.0.5-beta and API has changed dramatically without backward compatibility. Any code accessing it must be amended. It does not apply to lib/googleapi.php. See MDL-47297 +* Added an extra parameter to the function get_formatted_help_string() (default null) which is used to specify + additional string parameters. DEPRECATIONS: * completion_info->get_incomplete_criteria() is deprecated and will be removed in Moodle 3.0. diff --git a/lib/weblib.php b/lib/weblib.php index 7e56c1b1075..63e9b8cb500 100644 --- a/lib/weblib.php +++ b/lib/weblib.php @@ -3487,6 +3487,8 @@ function print_password_policy() { * @param boolean $ajax Whether this help is called from an AJAX script. * This is used to influence text formatting and determines * which format to output the doclink in. + * @param string|object|array $a An object, string or number that can be used + * within translation strings * @return Object An object containing: * - heading: Any heading that there may be for this help string. * - text: The wiki-formatted help string. @@ -3494,7 +3496,7 @@ function print_password_policy() { * CSS classes to apply to that link. Only present if $ajax = false. * - completedoclink: A text representation of the doclink. Only present if $ajax = true. */ -function get_formatted_help_string($identifier, $component, $ajax = false) { +function get_formatted_help_string($identifier, $component, $ajax = false, $a = null) { global $CFG, $OUTPUT; $sm = get_string_manager(); @@ -3521,7 +3523,7 @@ function get_formatted_help_string($identifier, $component, $ajax = false) { $options->overflowdiv = !$ajax; // Should be simple wiki only MDL-21695. - $data->text = format_text(get_string($identifier.'_help', $component), FORMAT_MARKDOWN, $options); + $data->text = format_text(get_string($identifier.'_help', $component, $a), FORMAT_MARKDOWN, $options); $helplink = $identifier . '_link'; if ($sm->string_exists($helplink, $component)) { // Link to further info in Moodle docs. From d55f3e03b160abcb2b5071a9f6d27f40832dd89b Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Fri, 19 Sep 2014 00:17:58 -0700 Subject: [PATCH 25/44] MDL-45758 tool_monitor: added help icon renderer Original issue - MDL-47152 --- .../classes/output/helpicon/renderable.php | 93 +++++++++++++++++++ .../classes/output/helpicon/renderer.php | 79 ++++++++++++++++ admin/tool/monitor/help.php | 62 +++++++++++++ admin/tool/monitor/help_ajax.php | 50 ++++++++++ 4 files changed, 284 insertions(+) create mode 100644 admin/tool/monitor/classes/output/helpicon/renderable.php create mode 100644 admin/tool/monitor/classes/output/helpicon/renderer.php create mode 100644 admin/tool/monitor/help.php create mode 100644 admin/tool/monitor/help_ajax.php diff --git a/admin/tool/monitor/classes/output/helpicon/renderable.php b/admin/tool/monitor/classes/output/helpicon/renderable.php new file mode 100644 index 00000000000..3cb0395ebde --- /dev/null +++ b/admin/tool/monitor/classes/output/helpicon/renderable.php @@ -0,0 +1,93 @@ +. + +/** + * The file for the renderable class for the tool_monitor help icon. + * + * @package tool_monitor + * @copyright 2014 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace tool_monitor\output\helpicon; + +defined('MOODLE_INTERNAL') || die; + +/** + * Renderable class for the tool_monitor help icon. + * + * @since Moodle 2.8 + * @package tool_monitor + * @copyright 2014 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class renderable implements \renderable { + + /** + * @var string $type the type we are displaying the help icon for (either rule or subscription). + */ + public $type; + + /** + * @var int $id the id of the type. + */ + public $id; + + /** + * The constructor. + * + * @param string $type the type we are displaying the help icon for (either rule or subscription). + * @param int $id the id of the type. + */ + public function __construct($type, $id) { + $this->type = $type; + $this->id = $id; + } + + /** + * Returns the string to display for the help icon. + * + * @param string $type the type we are displaying the help icon for (either rule or subscription). + * @param int $id the id of the type. + * @param boolean $ajax Whether this help is called from an AJAX script. + * This is used to influence text formatting and determines which format to output the doclink in. + * @return string|object|array $a An object, string or number that can be used within translation strings + */ + public static function get_help_string_parameters($type, $id, $ajax = false) { + if ($type == 'rule') { + $rule = \tool_monitor\rule_manager::get_rule($id); + + $langstring = new \stdClass(); + $langstring->eventname = $rule->get_event_name(); + $langstring->eventcomponent = $rule->get_plugin_name(); + $langstring->frequency = $rule->frequency; + $langstring->minutes = $rule->timewindow / MINSECS; + + return get_formatted_help_string('rulehelp', 'tool_monitor', $ajax, $langstring); + } + + // Must be a subscription. + $sub = \tool_monitor\subscription_manager::get_subscription($id); + + $langstring = new \stdClass(); + $langstring->eventname = $sub->get_event_name(); + $langstring->moduleinstance = $sub->get_instance_name(); + $langstring->frequency = $sub->frequency; + $langstring->minutes = $sub->timewindow / MINSECS; + + return get_formatted_help_string('subhelp', 'tool_monitor', $ajax, $langstring); + } +} diff --git a/admin/tool/monitor/classes/output/helpicon/renderer.php b/admin/tool/monitor/classes/output/helpicon/renderer.php new file mode 100644 index 00000000000..99025f2fd6c --- /dev/null +++ b/admin/tool/monitor/classes/output/helpicon/renderer.php @@ -0,0 +1,79 @@ +. + +/** + * The file for the renderer class for the tool_monitor help icon. + * + * @package tool_monitor + * @copyright 2014 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace tool_monitor\output\helpicon; + +defined('MOODLE_INTERNAL') || die; + +/** + * Renderer class for tool_monitor help icons. + * + * @since Moodle 2.8 + * @package tool_monitor + * @copyright 2014 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class renderer extends \plugin_renderer_base { + + /** + * Get the HTML for the help icon. + * + * @param renderable $renderable renderable widget + * + * @return string the HTML of the help icon to display. + */ + protected function render_renderable(renderable $renderable) { + global $CFG; + + // First get the help image icon. + $src = $this->pix_url('help'); + + if ($renderable->type == 'rule') { + $title = get_string('rulehelp', 'tool_monitor'); + } else { // Must be a subscription. + $title = get_string('subhelp', 'tool_monitor'); + } + + $alt = get_string('helpwiththis'); + + $attributes = array('src' => $src, 'alt' => $alt, 'class' => 'iconhelp'); + $output = \html_writer::empty_tag('img', $attributes); + + // Now create the link around it - we need https on loginhttps pages. + $urlparams = array(); + $urlparams['type'] = $renderable->type; + $urlparams['id'] = $renderable->id; + $urlparams['lang'] = current_language(); + $url = new \moodle_url($CFG->httpswwwroot . '/admin/tool/monitor/help.php', $urlparams); + + // Note: this title is displayed only if JS is disabled, otherwise the link will have the new ajax tooltip. + $title = get_string('helpprefix2', '', trim($title, ". \t")); + + $attributes = array('href' => $url, 'title' => $title, 'aria-haspopup' => 'true', 'target' => '_blank'); + $output = \html_writer::tag('a', $output, $attributes); + + // Now, finally the span. + return \html_writer::tag('span', $output, array('class' => 'helptooltip')); + } +} diff --git a/admin/tool/monitor/help.php b/admin/tool/monitor/help.php new file mode 100644 index 00000000000..572b4bab20d --- /dev/null +++ b/admin/tool/monitor/help.php @@ -0,0 +1,62 @@ +. + +/** + * Displays help on a new page. + * + * @copyright 2014 Mark Nelson + * @package tool_monitor + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +define('NO_MOODLE_COOKIES', true); + +require_once('../../../config.php'); + +$type = required_param('type', PARAM_ALPHA); +$id = required_param('id', PARAM_INT); +$lang = optional_param('lang', 'en', PARAM_LANG); + +// We don't actually modify the session here as we have NO_MOODLE_COOKIES set. +$SESSION->lang = $lang; + +$PAGE->set_url('/admin/tool/monitor/help.php'); +$PAGE->set_pagelayout('popup'); + +if ($type == 'rule') { + $item = \tool_monitor\rule_manager::get_rule($id); +} else { // Must be a subscription. + $item = \tool_monitor\subscription_manager::get_subscription($id); +} + +if ($item->courseid) { + $PAGE->set_context(context_course::instance($item->courseid)); +} else { // Must be system context. + $PAGE->set_context(context_system::instance()); +} + +// Get the help string data. +$data = tool_monitor\output\helpicon\renderable::get_help_string_parameters($type, $id); + +echo $OUTPUT->header(); +if (!empty($data->heading)) { + echo $OUTPUT->heading($data->heading, 1, 'helpheading'); +} +echo $data->text; +if (isset($data->completedoclink)) { + echo $data->completedoclink; +} +echo $OUTPUT->footer(); diff --git a/admin/tool/monitor/help_ajax.php b/admin/tool/monitor/help_ajax.php new file mode 100644 index 00000000000..429ff3b06df --- /dev/null +++ b/admin/tool/monitor/help_ajax.php @@ -0,0 +1,50 @@ +. + +/** + * Displays help via AJAX call. + * + * @copyright 2014 Mark Nelson + * @package tool_monitor + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +define('NO_MOODLE_COOKIES', true); +define('AJAX_SCRIPT', true); + +require_once('../../../config.php'); + +$type = required_param('type', PARAM_ALPHA); +$id = required_param('id', PARAM_INT); +$lang = optional_param('lang', 'en', PARAM_LANG); + +// We don't actually modify the session here as we have NO_MOODLE_COOKIES set. +$SESSION->lang = $lang; +$PAGE->set_url('/admin/tool/monitor/help_ajax.php'); + +if ($type == 'rule') { + $item = \tool_monitor\rule_manager::get_rule($id); +} else { // Must be a subscription. + $item = \tool_monitor\subscription_manager::get_subscription($id); +} + +if ($item->courseid) { + $PAGE->set_context(context_course::instance($item->courseid)); +} else { // Must be system context. + $PAGE->set_context(context_system::instance()); +} + +echo json_encode(tool_monitor\output\helpicon\renderable::get_help_string_parameters($type, $id, true)); From 4e18940f83b8beb835e9ecb41b007f41b19ae89d Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Fri, 19 Sep 2014 19:51:11 -0700 Subject: [PATCH 26/44] MDL-45758 tool_monitor: added help icon for subscriptions Original issue - MDL-47152 --- .../monitor/classes/output/managesubs/subs.php | 14 +++++++++++++- admin/tool/monitor/lang/en/tool_monitor.php | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/admin/tool/monitor/classes/output/managesubs/subs.php b/admin/tool/monitor/classes/output/managesubs/subs.php index 1195894724d..773f1be74bb 100644 --- a/admin/tool/monitor/classes/output/managesubs/subs.php +++ b/admin/tool/monitor/classes/output/managesubs/subs.php @@ -48,6 +48,11 @@ class subs extends \table_sql implements \renderable { */ protected $context; + /** + * @var \tool_monitor\output\helpicon\renderer the help icon renderer. + */ + protected $helpiconrenderer; + /** * Sets up the table_log parameters. * @@ -57,6 +62,8 @@ class subs extends \table_sql implements \renderable { * @param int $perpage Number of rules to display per page. */ public function __construct($uniqueid, \moodle_url $url, $courseid = 0, $perpage = 100) { + global $PAGE; + parent::__construct($uniqueid); $this->set_attribute('class', 'toolmonitor subscriptions generaltable generalbox'); @@ -76,6 +83,7 @@ class subs extends \table_sql implements \renderable { $this->pageable(true); $this->is_downloadable(false); $this->define_baseurl($url); + $this->helpiconrenderer = $PAGE->get_renderer('tool_monitor', 'helpicon'); } /** @@ -86,7 +94,11 @@ class subs extends \table_sql implements \renderable { * @return string html used to display the column field. */ public function col_name(\tool_monitor\subscription $sub) { - return $sub->get_name($this->context); + $name = $sub->get_name($this->context); + $helpicon = new \tool_monitor\output\helpicon\renderable('subscription', $sub->id); + $helpicon = $this->helpiconrenderer->render($helpicon); + + return $name . $helpicon; } /** diff --git a/admin/tool/monitor/lang/en/tool_monitor.php b/admin/tool/monitor/lang/en/tool_monitor.php index b1529b57bee..0e2bffc4bac 100644 --- a/admin/tool/monitor/lang/en/tool_monitor.php +++ b/admin/tool/monitor/lang/en/tool_monitor.php @@ -74,6 +74,8 @@ $string['selectplugin_help'] = "Select a plugin that you are interested in monit $string['subareyousure'] = 'Are you sure you want to delete this subscription for the rule "{$a}"?'; $string['subcreatesuccess'] = "Subscription successfully created"; $string['subdeletesuccess'] = "Subscription successfully removed"; +$string['subhelp'] = 'Subscription details'; +$string['subhelp_help'] = 'This subscription listens for when the event \'{$a->eventname}\' has been triggered in \'{$a->moduleinstance}\' {$a->frequency} time(s) in {$a->minutes} minute(s).'; $string['title'] = '{$a->coursename} : {$a->reportname}'; $string['tool/monitor:managerules'] = 'Manage event monitor rules'; $string['tool/monitor:subscribe'] = 'Subscribe to event monitor rules'; From c47eb61a48273b1c3849430296599eb4370aacde Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Fri, 19 Sep 2014 00:37:54 -0700 Subject: [PATCH 27/44] MDL-45758 tool_monitor: added help icon for rules Original issue - MDL-47152 --- .../monitor/classes/output/managesubs/rules.php | 14 +++++++++++++- admin/tool/monitor/lang/en/tool_monitor.php | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/admin/tool/monitor/classes/output/managesubs/rules.php b/admin/tool/monitor/classes/output/managesubs/rules.php index a336b6ba8bf..b4e7ace6568 100644 --- a/admin/tool/monitor/classes/output/managesubs/rules.php +++ b/admin/tool/monitor/classes/output/managesubs/rules.php @@ -48,6 +48,11 @@ class rules extends \table_sql implements \renderable { */ protected $context; + /** + * @var \tool_monitor\output\helpicon\renderer the help icon renderer. + */ + protected $helpiconrenderer; + /** * Sets up the table_log parameters. * @@ -57,6 +62,8 @@ class rules extends \table_sql implements \renderable { * @param int $perpage Number of rules to display per page. */ public function __construct($uniqueid, \moodle_url $url, $courseid = 0, $perpage = 100) { + global $PAGE; + parent::__construct($uniqueid); $this->set_attribute('class', 'toolmonitor subscriberules generaltable generalbox'); @@ -76,6 +83,7 @@ class rules extends \table_sql implements \renderable { $this->pageable(true); $this->is_downloadable(false); $this->define_baseurl($url); + $this->helpiconrenderer = $PAGE->get_renderer('tool_monitor', 'helpicon'); } /** @@ -86,7 +94,11 @@ class rules extends \table_sql implements \renderable { * @return string html used to display the column field. */ public function col_name(\tool_monitor\rule $rule) { - return $rule->get_name($this->context); + $name = $rule->get_name($this->context); + $helpicon = new \tool_monitor\output\helpicon\renderable('rule', $rule->id); + $helpicon = $this->helpiconrenderer->render($helpicon); + + return $name . $helpicon; } /** diff --git a/admin/tool/monitor/lang/en/tool_monitor.php b/admin/tool/monitor/lang/en/tool_monitor.php index 0e2bffc4bac..eb888f522bc 100644 --- a/admin/tool/monitor/lang/en/tool_monitor.php +++ b/admin/tool/monitor/lang/en/tool_monitor.php @@ -61,6 +61,8 @@ $string['processevents'] = 'Process events'; $string['ruleareyousure'] = 'Are you sure you want to delete rule "{$a}"?'; $string['rulecopysuccess'] = 'Rule successfully copied'; $string['ruledeletesuccess'] = 'Rule successfully deleted'; +$string['rulehelp'] = 'Rule details'; +$string['rulehelp_help'] = 'This rule listens for when the event \'{$a->eventname}\' in \'{$a->eventcomponent}\' has been triggered {$a->frequency} time(s) in {$a->minutes} minute(s).'; $string['rulenopermissions'] = 'You do not have permissions to "{$a} a rule"'; $string['rulescansubscribe'] = 'Rules you can subscribe to'; $string['selectcourse'] = 'Visit this report at course level to get a list of possible modules'; From 84be4f6af446e513767291c678321c0fb92708af Mon Sep 17 00:00:00 2001 From: Simey Lameze Date: Tue, 30 Sep 2014 10:51:33 +0800 Subject: [PATCH 28/44] MDL-45758 tool_monitor: add missing alt on manage icons Original issue - MDL-47460 --- .../monitor/classes/output/managerules/renderable.php | 6 +++--- admin/tool/monitor/classes/output/managesubs/subs.php | 3 ++- admin/tool/monitor/lang/en/tool_monitor.php | 8 ++++++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/admin/tool/monitor/classes/output/managerules/renderable.php b/admin/tool/monitor/classes/output/managerules/renderable.php index dabf3255b34..c2d958698d6 100644 --- a/admin/tool/monitor/classes/output/managerules/renderable.php +++ b/admin/tool/monitor/classes/output/managerules/renderable.php @@ -163,16 +163,16 @@ class renderable extends \table_sql implements \renderable { $deleteurl = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/managerules.php', array('ruleid' => $rule->id, 'action' => 'delete', 'courseid' => $rule->courseid)); - $icon = $OUTPUT->render(new \pix_icon('t/edit', '')); + $icon = $OUTPUT->render(new \pix_icon('t/edit', get_string('editrule', 'tool_monitor'))); $manage .= \html_writer::link($editurl, $icon, array('class' => 'action-icon')); - $icon = $OUTPUT->render(new \pix_icon('t/copy', '')); + $icon = $OUTPUT->render(new \pix_icon('t/copy', get_string('duplicaterule', 'tool_monitor'))); $manage .= \html_writer::link($copyurl, $icon, array('class' => 'action-icon')); $a = $rule->get_name($this->context); $action = new \component_action('click', 'M.util.show_confirm_dialog', array('message' => get_string('ruleareyousure', 'tool_monitor', $a))); - $icon = $OUTPUT->action_link($deleteurl, new \pix_icon('t/delete', ''), $action); + $icon = $OUTPUT->action_link($deleteurl, new \pix_icon('t/delete', get_string('deleterule', 'tool_monitor')), $action); $manage .= $icon; } else { $manage = '-'; diff --git a/admin/tool/monitor/classes/output/managesubs/subs.php b/admin/tool/monitor/classes/output/managesubs/subs.php index 773f1be74bb..493f96b8978 100644 --- a/admin/tool/monitor/classes/output/managesubs/subs.php +++ b/admin/tool/monitor/classes/output/managesubs/subs.php @@ -127,7 +127,8 @@ class subs extends \table_sql implements \renderable { 'action' => 'unsubscribe', 'courseid' => $this->courseid)); $action = new \component_action('click', 'M.util.show_confirm_dialog', array('message' => get_string('subareyousure', 'tool_monitor', $a))); - $icon = $OUTPUT->action_link($deleteurl, new \pix_icon('t/delete', ''), $action); + $icon = $OUTPUT->action_link($deleteurl, + new \pix_icon('t/delete', get_string('deletesubscription', 'tool_monitor')), $action); return $icon; } diff --git a/admin/tool/monitor/lang/en/tool_monitor.php b/admin/tool/monitor/lang/en/tool_monitor.php index eb888f522bc..1b67553d96f 100644 --- a/admin/tool/monitor/lang/en/tool_monitor.php +++ b/admin/tool/monitor/lang/en/tool_monitor.php @@ -31,9 +31,13 @@ $string['core'] = 'Core'; $string['customizefilters'] = 'Select the frequency of the events'; $string['customizemessage'] = 'Cutomize the notification message'; $string['currentsubscriptions'] = 'Your current subscriptions'; -$string['description'] = 'Description:'; $string['description_help'] = "Description is displayed to users when they want to subscribe to this rule. This helps them understand what the rule is about."; $string['defaultmessagetpl'] = 'Rule "{rulename}" has happened. You can find further details at {link}'; +$string['deleterule'] = 'Delete rule'; +$string['deletesubscription'] = 'Delete subscription'; +$string['description'] = 'Description:'; +$string['duplicaterule'] = 'Duplicate rule'; +$string['editrule'] = 'Edit rule'; $string['eventnotfound'] = 'Event not found'; $string['errorincorrectevent'] = 'Please select an event related to the selected plugin'; $string['freqdesc'] = '{$a->freq} times in {$a->mins} minutes'; @@ -59,7 +63,7 @@ $string['name_help'] = "Choose a name for the rule."; $string['pluginname'] = 'Event monitor'; $string['processevents'] = 'Process events'; $string['ruleareyousure'] = 'Are you sure you want to delete rule "{$a}"?'; -$string['rulecopysuccess'] = 'Rule successfully copied'; +$string['rulecopysuccess'] = 'Rule successfully duplicated'; $string['ruledeletesuccess'] = 'Rule successfully deleted'; $string['rulehelp'] = 'Rule details'; $string['rulehelp_help'] = 'This rule listens for when the event \'{$a->eventname}\' in \'{$a->eventcomponent}\' has been triggered {$a->frequency} time(s) in {$a->minutes} minute(s).'; From d18c425d513605e4d6deee831140957314f1adc7 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Fri, 26 Sep 2014 07:30:05 +0530 Subject: [PATCH 29/44] MDL-45758 tool_monitor: Add a new message provider Original issue - MDL-46132 --- admin/tool/monitor/db/messages.php | 32 +++++++++++++++++++++ admin/tool/monitor/lang/en/tool_monitor.php | 1 + 2 files changed, 33 insertions(+) create mode 100644 admin/tool/monitor/db/messages.php diff --git a/admin/tool/monitor/db/messages.php b/admin/tool/monitor/db/messages.php new file mode 100644 index 00000000000..e80f6ef2d2c --- /dev/null +++ b/admin/tool/monitor/db/messages.php @@ -0,0 +1,32 @@ +. + +/** + * Message providers list. + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$messageproviders = array ( + // Notify a user that a rule has happened. + 'notification' => array ( + 'capability' => 'tool/monitor:subscribe' + ) +); diff --git a/admin/tool/monitor/lang/en/tool_monitor.php b/admin/tool/monitor/lang/en/tool_monitor.php index 1b67553d96f..5825195ea10 100644 --- a/admin/tool/monitor/lang/en/tool_monitor.php +++ b/admin/tool/monitor/lang/en/tool_monitor.php @@ -50,6 +50,7 @@ $string['manage'] = 'Manage'; $string['managesubscriptions'] = 'Manage subscriptions'; $string['managerules'] = 'Manage rules'; $string['messageheader'] = 'Customize your notification message'; +$string['messageprovider:notification'] = 'Notifications of rule subscriptions'; $string['messagetemplate'] = 'Message template'; $string['messagetemplate_help'] = 'This is the content of the message that will be sent to users, when the given conditions of the rule are met. You are allowed to use following templates in this.
{link} - Link to the location where the event happened. From 01d070e74b357b08672ad8f06f994f72d7664cbd Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Wed, 1 Oct 2014 13:50:25 +0530 Subject: [PATCH 30/44] MDL-45758 tool_monitor: Modifiy manager classes to return instances Original issue - MDL-46132 --- .../classes/output/managerules/renderable.php | 4 +--- .../classes/output/managesubs/rules.php | 4 +--- .../classes/output/managesubs/subs.php | 4 +--- admin/tool/monitor/classes/rule_manager.php | 22 +++++++++++++++--- .../monitor/classes/subscription_manager.php | 23 +++++++++++++++---- 5 files changed, 41 insertions(+), 16 deletions(-) diff --git a/admin/tool/monitor/classes/output/managerules/renderable.php b/admin/tool/monitor/classes/output/managerules/renderable.php index c2d958698d6..8534d1be346 100644 --- a/admin/tool/monitor/classes/output/managerules/renderable.php +++ b/admin/tool/monitor/classes/output/managerules/renderable.php @@ -192,9 +192,7 @@ class renderable extends \table_sql implements \renderable { $this->pagesize($pagesize, $total); $rules = \tool_monitor\rule_manager::get_rules_by_courseid($this->courseid, $this->get_page_start(), $this->get_page_size()); - foreach ($rules as $rule) { - $this->rawdata[] = \tool_monitor\rule_manager::get_rule($rule); - } + $this->rawdata = $rules; // Set initial bars. if ($useinitialsbar) { $this->initialbars($total > $pagesize); diff --git a/admin/tool/monitor/classes/output/managesubs/rules.php b/admin/tool/monitor/classes/output/managesubs/rules.php index b4e7ace6568..d655a43f8e8 100644 --- a/admin/tool/monitor/classes/output/managesubs/rules.php +++ b/admin/tool/monitor/classes/output/managesubs/rules.php @@ -137,9 +137,7 @@ class rules extends \table_sql implements \renderable { $this->pagesize($pagesize, $total); $rules = \tool_monitor\rule_manager::get_rules_by_courseid($this->courseid, $this->get_page_start(), $this->get_page_size()); - foreach ($rules as $rule) { - $this->rawdata[] = \tool_monitor\rule_manager::get_rule($rule); - } + $this->rawdata = $rules; // Set initial bars. if ($useinitialsbar) { $this->initialbars($total > $pagesize); diff --git a/admin/tool/monitor/classes/output/managesubs/subs.php b/admin/tool/monitor/classes/output/managesubs/subs.php index 493f96b8978..1e93786a117 100644 --- a/admin/tool/monitor/classes/output/managesubs/subs.php +++ b/admin/tool/monitor/classes/output/managesubs/subs.php @@ -144,9 +144,7 @@ class subs extends \table_sql implements \renderable { $this->pagesize($pagesize, $total); $subs = \tool_monitor\subscription_manager::get_user_subscriptions_for_course($this->courseid, $this->get_page_start(), $this->get_page_size()); - foreach ($subs as $subscription) { - $this->rawdata[] = \tool_monitor\subscription_manager::get_subscription($subscription->id); - } + $this->rawdata = $subs; // Set initial bars. if ($useinitialsbar) { $this->initialbars($total > $pagesize); diff --git a/admin/tool/monitor/classes/rule_manager.php b/admin/tool/monitor/classes/rule_manager.php index 97ca8c5913b..864451cbd4c 100644 --- a/admin/tool/monitor/classes/rule_manager.php +++ b/admin/tool/monitor/classes/rule_manager.php @@ -142,7 +142,8 @@ class rule_manager { public static function get_rules_by_courseid($courseid, $limitfrom = 0, $limitto = 0) { global $DB; $select = "courseid = ? OR courseid = ?"; - return $DB->get_records_select('tool_monitor_rules', $select, array(0, $courseid), null, '*', $limitfrom, $limitto); + return self::get_instances($DB->get_records_select('tool_monitor_rules', $select, array(0, $courseid), null, '*', + $limitfrom, $limitto)); } /** @@ -167,7 +168,7 @@ class rule_manager { */ public static function get_rules_by_plugin($plugin) { global $DB; - return $DB->get_records('tool_monitor_rules', array('plugin' => $plugin)); + return self::get_instances($DB->get_records('tool_monitor_rules', array('plugin' => $plugin))); } /** @@ -179,6 +180,21 @@ class rule_manager { */ public static function get_rules_by_event($eventname) { global $DB; - return $DB->get_records('tool_monitor_rules', array('eventname' => $eventname)); + return self::get_instances($DB->get_records('tool_monitor_rules', array('eventname' => $eventname))); + } + + /** + * Helper method to convert db records to instances. + * + * @param array $arr of rules. + * + * @return array of rules as instances. + */ + protected static function get_instances($arr) { + $result = array(); + foreach ($arr as $key => $sub) { + $result[$key] = new rule($sub); + } + return $result; } } diff --git a/admin/tool/monitor/classes/subscription_manager.php b/admin/tool/monitor/classes/subscription_manager.php index 5c3e5efeb67..c7b67c593ba 100644 --- a/admin/tool/monitor/classes/subscription_manager.php +++ b/admin/tool/monitor/classes/subscription_manager.php @@ -136,7 +136,8 @@ class subscription_manager { $sql = self::get_subscription_join_rule_sql(); $sql .= "WHERE s.courseid = :courseid AND s.userid = :userid ORDER BY $order"; - return $DB->get_records_sql($sql, array('courseid' => $courseid, 'userid' => $userid), $limitfrom, $limitto); + return self::get_instances($DB->get_records_sql($sql, array('courseid' => $courseid, 'userid' => $userid), $limitfrom, + $limitto)); } /** @@ -158,7 +159,6 @@ class subscription_manager { return $DB->count_records_sql($sql, array('courseid' => $courseid, 'userid' => $userid)); } - /** * Return a list of subscriptions for a given event. * @@ -177,7 +177,7 @@ class subscription_manager { $sql .= "WHERE r.eventname = :eventname AND (s.courseid = :courseid OR s.courseid = 0)"; $params = array('eventname' => $event->eventname, 'courseid' => $event->courseid); } - return $DB->get_records_sql($sql, $params); + return self::get_instances($DB->get_records_sql($sql, $params)); } /** @@ -187,7 +187,7 @@ class subscription_manager { * * @return string the sql. */ - public static function get_subscription_join_rule_sql($count = false) { + protected static function get_subscription_join_rule_sql($count = false) { if ($count) { $select = "SELECT COUNT(s.id) "; } else { @@ -200,4 +200,19 @@ class subscription_manager { ON r.id = s.ruleid "; return $sql; } + + /** + * Helper method to convert db records to instances. + * + * @param array $arr of subscriptions. + * + * @return array of subscriptions as instances. + */ + protected static function get_instances($arr) { + $result = array(); + foreach ($arr as $key => $sub) { + $result[$key] = new subscription($sub); + } + return $result; + } } From 1ebfdaec04d23a8089b6838c03646867cd5aa9f7 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Fri, 26 Sep 2014 07:31:22 +0530 Subject: [PATCH 31/44] MDL-45758 tool_monitor: Add a adhock task to send notifications Original issue - MDL-46132 --- .../monitor/classes/notification_task.php | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 admin/tool/monitor/classes/notification_task.php diff --git a/admin/tool/monitor/classes/notification_task.php b/admin/tool/monitor/classes/notification_task.php new file mode 100644 index 00000000000..ffb1f4a6b57 --- /dev/null +++ b/admin/tool/monitor/classes/notification_task.php @@ -0,0 +1,118 @@ +. + +/** + * This file defines an adhoc task to send notifications. + * + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace tool_monitor; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Adhock class, used to send notifications to users. + * + * @since Moodle 2.8 + * @package tool_monitor + * @copyright 2014 onwards Ankit Agarwal + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class notification_task extends \core\task\adhoc_task { + + /** + * Send out messages. + */ + public function execute() { + foreach ($this->get_custom_data() as $data) { + $eventobj = $data->event; + $subscriptionids = $data->subscriptionids; + foreach ($subscriptionids as $id) { + if ($message = $this->generate_message($id, $eventobj)) { + message_send($message); + } + } + } + } + + /** + * Generates the message object for a give subscription and event. + * + * @param int $subscriptionid Subscription instance + * @param \stdClass $eventobj Event data + * + * @return false|\stdClass message object + */ + protected function generate_message($subscriptionid, \stdClass $eventobj) { + + try { + $subscription = subscription_manager::get_subscription($subscriptionid); + } catch (\dml_exception $e) { + // Race condition, someone deleted the subscription. + return false; + } + $user = \core_user::get_user($subscription->userid); + $context = \context_user::instance($user->id, IGNORE_MISSING); + if ($context === false) { + // User context doesn't exist. Should never happen, nothing to do return. + return false; + } + + $template = $subscription->template; + $template = $this->replace_placeholders($template, $subscription, $eventobj, $context); + $msgdata = new \stdClass(); + $msgdata->component = 'tool_monitor'; // Your component name. + $msgdata->name = 'notification'; // This is the message name from messages.php. + $msgdata->userfrom = \core_user::get_noreply_user(); + $msgdata->userto = $user; + $msgdata->subject = $subscription->get_name($context); + $msgdata->fullmessage = format_text($template, $subscription->templateformat, array('context' => $context)); + $msgdata->fullmessageformat = $subscription->templateformat; + $msgdata->fullmessagehtml = format_text($template, $subscription->templateformat, array('context' => $context)); + $msgdata->smallmessage = ''; + $msgdata->notification = 1; // This is only set to 0 for personal messages between users. + + return $msgdata; + } + + /** + * Replace place holders in the template with respective content. + * + * @param string $template Message template. + * @param subscription $subscription subscription instance + * @param \stdclass $eventobj Event data + * @param \context $context context object + * + * @return mixed final template string. + */ + protected function replace_placeholders($template, subscription $subscription, $eventobj, $context) { + $template = str_replace('{link}', $eventobj->link, $template); + if ($eventobj->contextlevel == CONTEXT_MODULE && !empty($eventobj->contextinstanceid) + && (strpos($template, '{modulelink}') !== false)) { + $cm = get_fast_modinfo($eventobj->courseid)->get_cm($eventobj->contextinstanceid); + $modulelink = $cm->url; + $template = str_replace('{modulelink}', $modulelink, $template); + } + $template = str_replace('{rulename}', $subscription->get_name($context), $template); + $template = str_replace('{description}', $subscription->get_description($context), $template); + $template = str_replace('{eventname}', $subscription->get_event_name(), $template); + + return $template; + } +} From bb550efc0d3302d1a16e56b38a2379e8b67b30bc Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Fri, 26 Sep 2014 07:35:05 +0530 Subject: [PATCH 32/44] MDL-45758 tool_monitor: Add a universal event observer This observer does the following task:- 1) It monitors all events and stores relevant data in a temporary table 2) It doesn't write the events straight away, it buffers them, so there is only one db write per request 3) It calculates and sees if there are subscriptions related to those events who need to be notified 4) If there are such cases, it schedules a adhoc task for the same Original issue - MDL-46132 --- admin/tool/monitor/classes/eventobservers.php | 138 ++++++++++++++++++ admin/tool/monitor/db/events.php | 4 + 2 files changed, 142 insertions(+) diff --git a/admin/tool/monitor/classes/eventobservers.php b/admin/tool/monitor/classes/eventobservers.php index 1a98d732f8c..a63dc0d3291 100644 --- a/admin/tool/monitor/classes/eventobservers.php +++ b/admin/tool/monitor/classes/eventobservers.php @@ -36,6 +36,15 @@ defined('MOODLE_INTERNAL') || die(); */ class eventobservers { + /** @var array $buffer buffer of events. */ + protected $buffer = array(); + + /** @var int Number of entries in the buffer. */ + protected $count = 0; + + /** @var eventobservers a reference to a self instance. */ + protected static $instance; + /** * Course delete event observer. * This observer monitors course delete event, and when a course is deleted it deletes any rules and subscriptions associated @@ -49,4 +58,133 @@ class eventobservers { rule_manager::delete_rule($rule->id); } } + + /** + * The observer monitoring all the events. + * + * This observers puts small event objects in buffer for later writing to the database. At the end of the request the buffer + * is cleaned up and all data dumped into the tool_monitor_events table. + * + * @param \core\event\base $event event object + */ + public static function process_event(\core\event\base $event) { + + if (empty(self::$instance)) { + self::$instance = new static(); + // Register shutdown handler - this is useful for buffering, processing events, etc. + \core_shutdown_manager::register_function(array(self::$instance, 'process_buffer')); + } + + self::$instance->buffer_event($event); + + if (PHPUNIT_TEST) { + // Process buffer after every event when unit testing. + self::$instance->process_buffer(); + + } + } + + /** + * Api to buffer events to store, to reduce db queries. + * + * @param \core\event\base $event + */ + protected function buffer_event(\core\event\base $event) { + + $eventdata = $event->get_data(); + $eventobj = new \stdClass(); + $eventobj->eventname = $eventdata['eventname']; + $eventobj->contextid = $eventdata['contextid']; + $eventobj->contextlevel = $eventdata['contextlevel']; + $eventobj->contextinstanceid = $eventdata['contextinstanceid']; + if ($event->get_url()) { + // Get link url if exists. + $eventobj->link = $event->get_url()->out(); + } else { + $eventobj->link = ''; + } + $eventobj->courseid = $eventdata['courseid']; + $eventobj->timecreated = $eventdata['timecreated']; + + $this->buffer[] = $eventobj; + $this->count++; + } + + /** + * This method process all events stored in the buffer. + * + * This is a multi purpose api. It does the following:- + * 1. Write event data to tool_monitor_events + * 2. Find out users that need to be notified about rule completion and schedule a task to send them messages. + */ + public function process_buffer() { + global $DB; + + $events = $this->flush(); // Flush data. + + $select = "SELECT COUNT(id) FROM {tool_monitor_events} "; + $now = time(); + $messagestosend = array(); + + // Let us now process the events and check for subscriptions. + foreach ($events as $eventobj) { + $subscriptions = subscription_manager::get_subscriptions_by_event($eventobj); + $idstosend = array(); + foreach ($subscriptions as $subscription) { + $starttime = $now - $subscription->timewindow; + if ($subscription->courseid == 0) { + // Site level subscription. Count all events. + $where = "eventname = :eventname AND timecreated > :starttime"; + $params = array('eventname' => $eventobj->eventname, 'starttime' => $starttime); + } else { + // Course level subscription. + if ($subscription->cmid == 0) { + // All modules. + $where = "eventname = :eventname AND courseid = :courseid AND timecreated > :starttime"; + $params = array('eventname' => $eventobj->eventname, 'courseid' => $eventobj->courseid, + 'starttime' => $starttime); + } else { + // Specific module. + $where = "eventname = :eventname AND courseid = :courseid AND contextinstanceid = :cmid + AND timecreated > :starttime"; + $params = array('eventname' => $eventobj->eventname, 'courseid' => $eventobj->courseid, + 'cmid' => $eventobj->contextinstanceid, 'starttime' => $starttime); + + } + } + $sql = $select . "WHERE " . $where; + $count = $DB->count_records_sql($sql, $params); + if (!empty($count) && $count >= $subscription->frequency) { + $idstosend[] = $subscription->id; + } + } + if (!empty($idstosend)) { + $messagestosend[] = array('subscriptionids' => $idstosend, 'event' => $eventobj); + } + } + + // Schedule a task to send notification. + if (!empty($messagestosend)) { + $adhocktask = new notification_task(); + $adhocktask->set_custom_data($messagestosend); + $adhocktask->set_component('tool_monitor'); + \core\task\manager::queue_adhoc_task($adhocktask); + } + } + + /** + * Protected method that flushes the buffer of events and writes them to the database. + * + * @return array a copy of the events buffer. + */ + protected function flush() { + global $DB; + + // Flush the buffer to the db. + $events = $this->buffer; + $DB->insert_records('tool_monitor_events', $events); // Insert the whole chunk into the database. + $this->buffer = array(); + $this->count = 0; + return $events; + } } diff --git a/admin/tool/monitor/db/events.php b/admin/tool/monitor/db/events.php index 169131b863f..4589c58c9f0 100644 --- a/admin/tool/monitor/db/events.php +++ b/admin/tool/monitor/db/events.php @@ -27,5 +27,9 @@ $observers = array( array( 'eventname' => '\core\event\course_deleted', 'callback' => '\tool_monitor\eventobservers::course_deleted', + ), + array( + 'eventname' => '*', + 'callback' => '\tool_monitor\eventobservers::process_event', ) ); From 5833307eab8a3ed8f9e4486bb9e79268219a79b3 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Fri, 26 Sep 2014 07:35:38 +0530 Subject: [PATCH 33/44] MDL-45758 tool_monitor: Add unit tests for the universal observer Original issue - MDL-46132 --- .../monitor/tests/eventobservers_test.php | 278 +++++++++++++++++- 1 file changed, 277 insertions(+), 1 deletion(-) diff --git a/admin/tool/monitor/tests/eventobservers_test.php b/admin/tool/monitor/tests/eventobservers_test.php index c097e5566f0..a8a1f60d32e 100644 --- a/admin/tool/monitor/tests/eventobservers_test.php +++ b/admin/tool/monitor/tests/eventobservers_test.php @@ -18,13 +18,22 @@ * Unit tests for event observers. * * @package tool_monitor - * @category phpunit + * @category test * @copyright 2014 onwards Ankit Agarwal * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); +global $CFG; +require_once($CFG->dirroot . '/blog/locallib.php'); +require_once($CFG->dirroot . '/blog/lib.php'); + +/** + * Class tool_monitor_eventobservers_testcase + * + * Tests for event observers + */ class tool_monitor_eventobservers_testcase extends advanced_testcase { /** @@ -88,4 +97,271 @@ class tool_monitor_eventobservers_testcase extends advanced_testcase { $coursesubs = \tool_monitor\subscription_manager::get_user_subscriptions_for_course($course->id, 0, 0, $user->id); $this->assertCount(0, $coursesubs); // Making sure all subscriptions are deleted. } + + /** + * This tests if writing of the events to the table tool_monitor_events is working fine. + */ + public function test_flush() { + global $DB; + + $this->resetAfterTest(); + + // Create events and verify data is fine. + $course = $this->getDataGenerator()->create_course(); + + $initialevents = $DB->get_records('tool_monitor_events'); + $initalcount = count($initialevents); + $event = \mod_book\event\course_module_instance_list_viewed::create_from_course($course); + $event->trigger(); + + $events = $DB->get_records('tool_monitor_events'); + $count = count($events); + $this->assertEquals($initalcount + 1, $count); + $monitorevent = array_pop($events); + + // Match values. + $this->assertEquals($event->eventname, $monitorevent->eventname); + $this->assertEquals($event->contextid, $monitorevent->contextid); + $this->assertEquals($event->contextlevel, $monitorevent->contextlevel); + $this->assertEquals($event->get_url()->out(), $monitorevent->link); + $this->assertEquals($event->courseid, $monitorevent->courseid); + $this->assertEquals($event->timecreated, $monitorevent->timecreated); + } + + /** + * Test the notification sending features. + */ + public function test_process_event() { + + global $DB, $USER; + + $this->resetAfterTest(); + $this->setAdminUser(); + $msgsink = $this->redirectMessages(); + + // Generate data. + $course = $this->getDataGenerator()->create_course(); + $toolgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor'); + + $rulerecord = new stdClass(); + $rulerecord->courseid = $course->id; + $rulerecord->eventname = '\mod_book\event\course_module_instance_list_viewed'; + $rulerecord->frequency = 1; + + $rule = $toolgenerator->create_rule($rulerecord); + + $subrecord = new stdClass(); + $subrecord->courseid = $course->id; + $subrecord->ruleid = $rule->id; + $subrecord->userid = $USER->id; + $toolgenerator->create_subscription($subrecord); + + $recordexists = $DB->record_exists('task_adhoc', array('component' => 'tool_monitor')); + $this->assertFalse($recordexists); + + // Now let us trigger the event. + $event = \mod_book\event\course_module_instance_list_viewed::create_from_course($course); + $event->trigger(); + + $this->verify_processed_data($msgsink); + + // Clean up. + \tool_monitor\rule_manager::delete_rule($rule->id); + $DB->delete_records('tool_monitor_events'); + + // Let us create a rule with more than 1 frequency. + $rulerecord->frequency = 5; + $rule = $toolgenerator->create_rule($rulerecord); + $subrecord->ruleid = $rule->id; + $toolgenerator->create_subscription($subrecord); + + // Let us trigger events. + for ($i = 0; $i < 5; $i++) { + $event = \mod_book\event\course_module_instance_list_viewed::create_from_course($course); + $event->trigger(); + if ($i != 4) { + $this->verify_message_not_sent_yet($msgsink); + } + } + + $this->verify_processed_data($msgsink); + + // Clean up. + \tool_monitor\rule_manager::delete_rule($rule->id); + $DB->delete_records('tool_monitor_events'); + + // Now let us create a rule specific to a module instance. + $cm = new stdClass(); + $cm->course = $course->id; + $book = $this->getDataGenerator()->create_module('book', $cm); + $rulerecord->eventname = '\mod_book\event\course_module_viewed'; + $rulerecord->cmid = $book->cmid; + $rule = $toolgenerator->create_rule($rulerecord); + $subrecord->ruleid = $rule->id; + $toolgenerator->create_subscription($subrecord); + + // Let us trigger events. + $params = array( + 'context' => context_module::instance($book->cmid), + 'objectid' => $book->id + ); + for ($i = 0; $i < 5; $i++) { + $event = \mod_book\event\course_module_viewed::create($params); + $event->trigger(); + if ($i != 4) { + $this->verify_message_not_sent_yet($msgsink); + } + } + + $this->verify_processed_data($msgsink); + + // Clean up. + \tool_monitor\rule_manager::delete_rule($rule->id); + $DB->delete_records('tool_monitor_events'); + + // Now let us create a rule for event that happens in category context events. + $rulerecord->eventname = '\core\event\course_category_created'; + $rulerecord->courseid = 0; + $rule = $toolgenerator->create_rule($rulerecord); + $subrecord->courseid = 0; + $subrecord->ruleid = $rule->id; + $toolgenerator->create_subscription($subrecord); + + // Let us trigger events. + for ($i = 0; $i < 5; $i++) { + $this->getDataGenerator()->create_category(); + if ($i != 4) { + $this->verify_message_not_sent_yet($msgsink); + } + } + $this->verify_processed_data($msgsink); + + // Clean up. + \tool_monitor\rule_manager::delete_rule($rule->id); + $DB->delete_records('tool_monitor_events'); + + // Now let us create a rule at site level. + $rulerecord->eventname = '\core\event\blog_entry_created'; + $rulerecord->courseid = 0; + $rule = $toolgenerator->create_rule($rulerecord); + $subrecord->courseid = 0; + $subrecord->ruleid = $rule->id; + $toolgenerator->create_subscription($subrecord); + + // Let us trigger events. + $blog = new blog_entry(); + $blog->subject = "Subject of blog"; + $blog->userid = $USER->id; + $states = blog_entry::get_applicable_publish_states(); + $blog->publishstate = reset($states); + for ($i = 0; $i < 5; $i++) { + $newblog = fullclone($blog); + $newblog->add(); + if ($i != 4) { + $this->verify_message_not_sent_yet($msgsink); + } + } + + $this->verify_processed_data($msgsink); + } + + /** + * Run adhoc tasks. + */ + protected function run_adhock_tasks() { + while ($task = \core\task\manager::get_next_adhoc_task(time())) { + $task->execute(); + \core\task\manager::adhoc_task_complete($task); + } + } + + /** + * Verify that task was scheduled and a message was sent as expected. + * + * @param phpunit_message_sink $msgsink Message sink + */ + protected function verify_processed_data(phpunit_message_sink $msgsink) { + global $DB, $USER; + + $recordexists = $DB->count_records('task_adhoc', array('component' => 'tool_monitor')); + $this->assertEquals(1, $recordexists); // We should have an adhock task now to send notifications. + $this->run_adhock_tasks(); + $this->assertEquals(1, $msgsink->count()); + $msgs = $msgsink->get_messages(); + $msg = array_pop($msgs); + $this->assertEquals($USER->id, $msg->useridto); + $this->assertEquals(1, $msg->notification); + $msgsink->clear(); + } + + /** + * Verify that a message was not sent. + * + * @param phpunit_message_sink $msgsink Message sink + */ + protected function verify_message_not_sent_yet(phpunit_message_sink $msgsink) { + $msgs = $msgsink->get_messages(); + $this->assertCount(0, $msgs); + $msgsink->clear(); + } + + /** + * Tests for replace_placeholders method. + */ + public function test_replace_placeholders() { + global $USER; + + $this->resetAfterTest(); + $this->setAdminUser(); + $msgsink = $this->redirectMessages(); + + // Generate data. + $course = $this->getDataGenerator()->create_course(); + $toolgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor'); + $context = \context_user::instance($USER->id, IGNORE_MISSING); + + // Creating book. + $cm = new stdClass(); + $cm->course = $course->id; + $book = $this->getDataGenerator()->create_module('book', $cm); + + // Creating rule. + $rulerecord = new stdClass(); + $rulerecord->courseid = $course->id; + $rulerecord->eventname = '\mod_book\event\course_module_viewed'; + $rulerecord->cmid = $book->cmid; + $rulerecord->frequency = 1; + $rulerecord->template = '{link} {modulelink} {rulename} {description} {eventname}'; + + $rule = $toolgenerator->create_rule($rulerecord); + + // Creating subscription. + $subrecord = new stdClass(); + $subrecord->courseid = $course->id; + $subrecord->ruleid = $rule->id; + $subrecord->userid = $USER->id; + $toolgenerator->create_subscription($subrecord); + + // Now let us trigger the event. + $params = array( + 'context' => context_module::instance($book->cmid), + 'objectid' => $book->id + ); + + $event = \mod_book\event\course_module_viewed::create($params); + $event->trigger(); + $this->run_adhock_tasks(); + $msgs = $msgsink->get_messages(); + $msg = array_pop($msgs); + + $modurl = new moodle_url('/mod/book/view.php', array('id' => $book->cmid)); + $expectedmsg = $event->get_url()->out() . ' ' . + $modurl->out() . ' ' . + $rule->get_name($context) . ' ' . + $rule->get_description($context) . ' ' . + $rule->get_event_name(); + + $this->assertEquals($expectedmsg, $msg->fullmessage); + } + } From e24e0d24b9a3278f9e6310505f1e83a91ac01bf0 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Thu, 2 Oct 2014 12:15:51 +0530 Subject: [PATCH 34/44] MDL-45758 tool_monitor: Add observers to handle user and module deletion Original issue - MDL-47376 --- admin/tool/monitor/classes/eventobservers.php | 20 ++++++++++++++++ .../monitor/classes/subscription_manager.php | 24 +++++++++++++++++++ admin/tool/monitor/db/events.php | 9 +++++++ 3 files changed, 53 insertions(+) diff --git a/admin/tool/monitor/classes/eventobservers.php b/admin/tool/monitor/classes/eventobservers.php index a63dc0d3291..27d3d296adc 100644 --- a/admin/tool/monitor/classes/eventobservers.php +++ b/admin/tool/monitor/classes/eventobservers.php @@ -187,4 +187,24 @@ class eventobservers { $this->count = 0; return $events; } + + /** + * Observer that monitors user deleted event and delete user subscriptions. + * + * @param \core\event\user_deleted $event the event object. + */ + public static function user_deleted(\core\event\user_deleted $event) { + $userid = $event->objectid; + subscription_manager::delete_user_subscriptions($userid); + } + + /** + * Observer that monitors course module deleted event and delete user subscriptions. + * + * @param \core\event\course_module_deleted $event the event object. + */ + public static function course_module_deleted(\core\event\course_module_deleted $event) { + $cmid = $event->contextinstanceid; + subscription_manager::delete_cm_subscriptions($cmid); + } } diff --git a/admin/tool/monitor/classes/subscription_manager.php b/admin/tool/monitor/classes/subscription_manager.php index c7b67c593ba..3d4d0f3561c 100644 --- a/admin/tool/monitor/classes/subscription_manager.php +++ b/admin/tool/monitor/classes/subscription_manager.php @@ -84,6 +84,30 @@ class subscription_manager { return $DB->delete_records('tool_monitor_subscriptions', array('id' => $subscription->id)); } + /** + * Delete all subscriptions for a user. + * + * @param int $userid user id. + * + * @return mixed + */ + public static function delete_user_subscriptions($userid) { + global $DB; + return $DB->delete_records('tool_monitor_subscriptions', array('userid' => $userid)); + } + + /** + * Delete all subscriptions for a course module. + * + * @param int $cmid cm id. + * + * @return mixed + */ + public static function delete_cm_subscriptions($cmid) { + global $DB; + return $DB->delete_records('tool_monitor_subscriptions', array('cmid' => $cmid)); + } + /** * Delete all subscribers for a given rule. * diff --git a/admin/tool/monitor/db/events.php b/admin/tool/monitor/db/events.php index 4589c58c9f0..0b1859fa510 100644 --- a/admin/tool/monitor/db/events.php +++ b/admin/tool/monitor/db/events.php @@ -26,10 +26,19 @@ $observers = array( array( 'eventname' => '\core\event\course_deleted', + 'priority' => 1, 'callback' => '\tool_monitor\eventobservers::course_deleted', ), array( 'eventname' => '*', 'callback' => '\tool_monitor\eventobservers::process_event', + ), + array( + 'eventname' => '\core\event\user_deleted', + 'callback' => '\tool_monitor\eventobservers::user_deleted', + ), + array( + 'eventname' => '\core\event\course_module_deleted', + 'callback' => '\tool_monitor\eventobservers::course_module_deleted', ) ); From 2161de73d8b952b57d2a016a042a920e3ab51b8f Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Thu, 2 Oct 2014 12:15:04 +0530 Subject: [PATCH 35/44] MDL-45758 tool_monitor: Add tests for the observers Original issue - MDL-47376 --- .../monitor/tests/eventobservers_test.php | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/admin/tool/monitor/tests/eventobservers_test.php b/admin/tool/monitor/tests/eventobservers_test.php index a8a1f60d32e..b8d178ab73d 100644 --- a/admin/tool/monitor/tests/eventobservers_test.php +++ b/admin/tool/monitor/tests/eventobservers_test.php @@ -364,4 +364,119 @@ class tool_monitor_eventobservers_testcase extends advanced_testcase { $this->assertEquals($expectedmsg, $msg->fullmessage); } + /** + * Test observer for user delete event. + */ + public function test_user_deleted() { + global $DB; + + $this->setAdminUser(); + $this->resetAfterTest(true); + + $user = $this->getDataGenerator()->create_user(); + $course = $this->getDataGenerator()->create_course(); + $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor'); + + $rule = new stdClass(); + $rule->userid = $user->id; + $rule->courseid = $course->id; + $rule->plugin = 'test'; + + $sub = new stdClass(); + $sub->courseid = $course->id; + $sub->userid = $user->id; + + // Add 10 rules for this course with subscriptions. + for ($i = 0; $i < 10; $i++) { + $createdrule = $monitorgenerator->create_rule($rule); + $sub->ruleid = $createdrule->id; + $monitorgenerator->create_subscription($sub); + } + + // Add 10 random rules for random courses. + for ($i = 0; $i < 10; $i++) { + $rule->courseid = rand(10000000, 50000000); + $createdrule = $monitorgenerator->create_rule($rule); + $sub->courseid = $rule->courseid; + $sub->ruleid = $createdrule->id; + $monitorgenerator->create_subscription($sub); + } + + // Verify data before user delete. + $totalrules = \tool_monitor\rule_manager::get_rules_by_plugin('test'); + $this->assertCount(20, $totalrules); + $totalsubs = $DB->get_records('tool_monitor_subscriptions'); + $this->assertCount(20, $totalsubs); + + // Let us delete the user now. + delete_user($user); + + // Verify data after course delete. + $totalrules = \tool_monitor\rule_manager::get_rules_by_plugin('test'); + $this->assertCount(20, $totalrules); + $totalsubs = $DB->get_records('tool_monitor_subscriptions'); + $this->assertCount(0, $totalsubs); // Make sure all subscriptions are deleted. + } + + /** + * Test observer for course module delete event. + */ + public function test_course_module_deleted() { + global $DB; + + $this->setAdminUser(); + $this->resetAfterTest(true); + + $user = $this->getDataGenerator()->create_user(); + $course = $this->getDataGenerator()->create_course(); + $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor'); + + // Now let us create a rule specific to a module instance. + $cm = new stdClass(); + $cm->course = $course->id; + $book = $this->getDataGenerator()->create_module('book', $cm); + + $rule = new stdClass(); + $rule->userid = $user->id; + $rule->courseid = $course->id; + $rule->plugin = 'test'; + + $sub = new stdClass(); + $sub->courseid = $course->id; + $sub->userid = $user->id; + $sub->cmid = $book->cmid; + + // Add 10 rules for this course with subscriptions for this module. + for ($i = 0; $i < 10; $i++) { + $createdrule = $monitorgenerator->create_rule($rule); + $sub->ruleid = $createdrule->id; + $monitorgenerator->create_subscription($sub); + } + + // Add 10 random rules for random courses. + for ($i = 0; $i < 10; $i++) { + $rule->courseid = rand(10000000, 50000000); + $createdrule = $monitorgenerator->create_rule($rule); + $sub->courseid = $rule->courseid; + $sub->ruleid = $createdrule->id; + $sub->cmid = 0; + $monitorgenerator->create_subscription($sub); + } + + // Verify data before module delete. + $totalrules = \tool_monitor\rule_manager::get_rules_by_plugin('test'); + $this->assertCount(20, $totalrules); + $totalsubs = $DB->get_records('tool_monitor_subscriptions'); + $this->assertCount(20, $totalsubs); + + // Let us delete the user now. + course_delete_module($book->cmid); + + // Verify data after course delete. + $totalrules = \tool_monitor\rule_manager::get_rules_by_plugin('test'); + $this->assertCount(20, $totalrules); + $totalsubs = $DB->get_records('tool_monitor_subscriptions'); + $this->assertCount(10, $totalsubs); // Make sure only relevant subscriptions are deleted. + } + } From 9031b34da328aa15d2d48720224b1ace712becc0 Mon Sep 17 00:00:00 2001 From: Simey Lameze Date: Fri, 3 Oct 2014 14:36:22 +0800 Subject: [PATCH 36/44] MDL-45758 tool_monitor: Behat tests for rule management Original issue - MDL-47148 --- admin/tool/monitor/tests/behat/rule.feature | 161 ++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 admin/tool/monitor/tests/behat/rule.feature diff --git a/admin/tool/monitor/tests/behat/rule.feature b/admin/tool/monitor/tests/behat/rule.feature new file mode 100644 index 00000000000..3e236fa7a10 --- /dev/null +++ b/admin/tool/monitor/tests/behat/rule.feature @@ -0,0 +1,161 @@ +@javascript @tool @tool_monitor @tool_monitor_rule +Feature: tool_monitor_rule + In order to manage rules + As an admin + I need to create a rule, edit a rule, duplicate a rule and delete a rule + + Background: + Given the following "courses" exist: + | fullname | shortname | + | Course 1 | C1 | + And the following "users" exist: + | username | firstname | lastname | email | + | teacher1 | Teacher | 1 | teacher1@asd.com | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + And I log in as "admin" + And I follow "Course 1" + And I navigate to "Manage rules" node in "Course administration > Reports > Event monitor" + And I press "Add a new rule" + And I set the following fields to these values: + | name | New rule course level | + | plugin | Forum | + | eventname | Post created | + | id_description | I want a rule to monitor posts created on a forum | + | frequency | 1 | + | minutes | 1 | + | Message template | The forum post was created. {modulelink} | + And I press "Save changes" + And I navigate to "Manage rules" node in "Site administration > Reports > Event monitor" + And I press "Add a new rule" + And I set the following fields to these values: + | name | New rule site level | + | plugin | Forum | + | eventname | Post created | + | id_description | I want a rule to monitor posts created on a forum | + | frequency | 1 | + | minutes | 1 | + | Message template | The forum post was created. {modulelink} | + And I press "Save changes" + And I log out + + Scenario: Add a rule on course level + Given I log in as "teacher1" + And I am on homepage + And I follow "Course 1" + And I navigate to "Manage rules" node in "Course administration > Reports > Event monitor" + When I press "Add a new rule" + And I set the following fields to these values: + | name | New rule | + | plugin | Forum | + | eventname | Post created | + | id_description | I want a rule to monitor posts created on a forum | + | frequency | 1 | + | minutes | 1 | + | Message template | The forum post was created. {modulelink} | + And I press "Save changes" + Then I should see "New rule" + And I should see "I want a rule to monitor posts created on a forum" + And I should see "Forum" + And I should see "Post created" + And I should see "1 times in 1 minutes" + + Scenario: Delete a rule on course level + Given I log in as "teacher1" + And I follow "Course 1" + And I navigate to "Manage rules" node in "Course administration > Reports > Event monitor" + When I click on "Delete rule" "link" + Then I should see "Are you sure you want to delete rule \"New rule course level\"?" + And I press "Yes" + And I should see "Rule successfully deleted" + And I should not see "New rule course level" + + Scenario: Edit a rule on course level + Given I log in as "teacher1" + And I follow "Course 1" + And I navigate to "Manage rules" node in "Course administration > Reports > Event monitor" + When I click on "Edit rule" "link" + And I set the following fields to these values: + | name | New rule quiz | + | plugin | Quiz | + | eventname | Quiz attempt deleted | + | id_description | I want a rule to monitor quiz attempts deleted | + | frequency | 5 | + | minutes | 5 | + | Message template | Quiz attempt deleted. {modulelink} | + And I press "Save changes" + Then I should see "New rule quiz" + And I should see "I want a rule to monitor quiz attempts deleted" + And I should see "Quiz attempt deleted" + And I should see "5 times in 5 minutes" + + Scenario: Duplicate a rule on course level + Given I log in as "teacher1" + And I follow "Course 1" + And I navigate to "Manage rules" node in "Course administration > Reports > Event monitor" + When I click on "Duplicate rule" "link" + Then I should see "Rule successfully duplicated" + And "#toolmonitorrules_r1" "css_element" should appear before "#toolmonitorrules_r2" "css_element" + And I should see "New rule" + And I should see "I want a rule to monitor posts created on a forum" + And I should see "Forum" + And I should see "Post created" + And I should see "1 times in 1 minutes" + + Scenario: Add a rule on site level + Given I log in as "admin" + And I navigate to "Manage rules" node in "Site administration > Reports > Event monitor" + When I press "Add a new rule" + And I set the following fields to these values: + | name | New rule | + | plugin | Forum | + | eventname | Post created | + | id_description | I want a rule to monitor posts created on a forum | + | frequency | 1 | + | minutes | 1 | + | Message template | The forum post was created. {modulelink} | + And I press "Save changes" + Then I should see "New rule" + And I should see "I want a rule to monitor posts created on a forum" + And I should see "Forum" + And I should see "Post created" + And I should see "1 times in 1 minutes" + + Scenario: Delete a rule on site level + Given I log in as "admin" + And I navigate to "Manage rules" node in "Site administration > Reports > Event monitor" + When I click on "Delete rule" "link" + Then I should see "Are you sure you want to delete rule \"New rule site level\"?" + And I press "Yes" + And I should see "Rule successfully deleted" + And I should not see "New rule site level" + + Scenario: Edit a rule on site level + Given I log in as "admin" + And I navigate to "Manage rules" node in "Site administration > Reports > Event monitor" + When I click on "Edit rule" "link" + And I set the following fields to these values: + | name | New Rule Quiz | + | plugin | Quiz | + | eventname | Quiz attempt deleted | + | id_description | I want a rule to monitor quiz attempts deleted | + | frequency | 5 | + | minutes | 5 | + | Message template | Quiz attempt deleted. {modulelink} | + And I press "Save changes" + Then I should see "New Rule Quiz" + And I should see "I want a rule to monitor quiz attempts deleted" + And I should see "Quiz attempt deleted" + And I should see "5 times in 5 minutes" + + Scenario: Duplicate a rule on site level + Given I log in as "admin" + And I navigate to "Manage rules" node in "Site administration > Reports > Event monitor" + When I click on "Duplicate rule" "link" + Then I should see "Rule successfully duplicated" + And "#toolmonitorrules_r2" "css_element" should appear after "#toolmonitorrules_r1" "css_element" + And I should see "I want a rule to monitor posts created on a forum" + And I should see "Forum" + And I should see "Post created" + And I should see "1 times in 1 minutes" From 77098e6dc14f7cdf59e9cd4cd583abc350e28bef Mon Sep 17 00:00:00 2001 From: Simey Lameze Date: Fri, 3 Oct 2014 14:37:00 +0800 Subject: [PATCH 37/44] MDL-45758 tool_monitor: Add behat tests to subscription management Original issue - MDL-47148 --- .../monitor/tests/behat/subscription.feature | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 admin/tool/monitor/tests/behat/subscription.feature diff --git a/admin/tool/monitor/tests/behat/subscription.feature b/admin/tool/monitor/tests/behat/subscription.feature new file mode 100644 index 00000000000..7f77bad73e8 --- /dev/null +++ b/admin/tool/monitor/tests/behat/subscription.feature @@ -0,0 +1,119 @@ +@javascript @tool @tool_monitor @tool_monitor_subscriptions +Feature: tool_monitor_subscriptions + In order to monitor events and receive notifications + As an user + I need to create a new rule, subscribe to it, receive notification and delete subscription + + Background: + Given the following "courses" exist: + | fullname | shortname | + | Course 1 | C1 | + And the following "users" exist: + | username | firstname | lastname | email | + | teacher1 | Teacher | 1 | teacher1@asd.com | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + And I log in as "admin" + And I follow "Course 1" + And I navigate to "Manage rules" node in "Course administration > Reports > Event monitor" + And I press "Add a new rule" + And I set the following fields to these values: + | name | New rule course level | + | plugin | Core | + | eventname | Course viewed | + | id_description | I want a rule to monitor when a course is viewed. | + | frequency | 1 | + | minutes | 1 | + | Message template | The course was viewed. {modulelink} | + And I press "Save changes" + And I navigate to "Manage rules" node in "Site administration > Reports > Event monitor" + And I press "Add a new rule" + And I set the following fields to these values: + | name | New rule site level | + | plugin | Core | + | eventname | Course viewed | + | id_description | I want a rule to monitor when a course is viewed. | + | frequency | 1 | + | minutes | 1 | + | Message template | The course was viewed. {modulelink} | + And I press "Save changes" + And I log out + + Scenario: Subscribe to a rule on course level + Given I log in as "teacher1" + And I follow "Course 1" + And I navigate to "Manage subscriptions" node in "Course administration > Reports > Event monitor" + When I set the field "cmid" to "All events" + Then I should see "Subscription successfully created" + And "#toolmonitorsubs_r0" "css_element" should exist + + Scenario: Delete a subscription on course level + Given I log in as "teacher1" + And I follow "Course 1" + And I navigate to "Manage subscriptions" node in "Course administration > Reports > Event monitor" + And I set the field "cmid" to "All events" + And I should see "Subscription successfully created" + When I click on "Delete subscription" "link" + And I should see "Are you sure you want to delete this subscription for the rule \"New rule course level\"?" + And I press "Yes" + Then I should see "Subscription successfully removed" + And "#toolmonitorsubs_r0" "css_element" should not exist + + Scenario: Subscribe to a rule on site level + Given I log in as "admin" + And I navigate to "Manage subscriptions" node in "Site administration > Reports > Event monitor" + When I set the field "cmid" to "All events" + Then I should see "Subscription successfully created" + And "#toolmonitorsubs_r0" "css_element" should exist + + Scenario: Delete a subscription on site level + Given I log in as "admin" + And I navigate to "Manage subscriptions" node in "Site administration > Reports > Event monitor" + And I set the field "cmid" to "All events" + And I should see "Subscription successfully created" + And "#toolmonitorsubs_r0" "css_element" should exist + When I click on "Delete subscription" "link" + And I should see "Are you sure you want to delete this subscription for the rule \"New rule site level\"?" + And I press "Yes" + Then I should see "Subscription successfully removed" + And "#toolmonitorsubs_r0" "css_element" should not exist + + Scenario: Receiving notification on site level + Given I log in as "admin" + And I navigate to "Messaging" node in "My profile settings" + And I click on "input[name^=tool_monitor_notification_loggedin]" "css_element" + And I press "Update profile" + And I am on homepage + And I follow "Course 1" + And I navigate to "Manage subscriptions" node in "Site administration > Reports > Event monitor" + And I set the field "cmid" to "All events" + And I should see "Subscription successfully created" + And "#toolmonitorsubs_r0" "css_element" should exist + And I am on homepage + And I trigger cron + And I am on homepage + And I expand "My profile" node + When I follow "Messages" + And I follow "Do not reply to this email (1)" + Then I should see "The course was viewed." + + Scenario: Receiving notification on course level + Given I log in as "teacher1" + And I navigate to "Messaging" node in "My profile settings" + And I click on "input[name^=tool_monitor_notification_loggedin]" "css_element" + And I press "Update profile" + And I am on homepage + And I follow "Course 1" + And I navigate to "Manage subscriptions" node in "Course administration > Reports > Event monitor" + And I set the field "cmid" to "All events" + And I should see "Subscription successfully created" + And "#toolmonitorsubs_r0" "css_element" should exist + And I am on homepage + And I follow "Course 1" + And I trigger cron + And I am on homepage + And I expand "My profile" node + When I follow "Messages" + And I follow "Do not reply to this email (1)" + Then I should see "The course was viewed." From 758793d88923e5cde24866833fad119f2f6952d1 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Mon, 6 Oct 2014 09:04:56 +0530 Subject: [PATCH 38/44] MDL-45758 tool_monitor: Fix lang strings for caps --- admin/tool/monitor/lang/en/tool_monitor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/admin/tool/monitor/lang/en/tool_monitor.php b/admin/tool/monitor/lang/en/tool_monitor.php index 5825195ea10..6afa1927e3c 100644 --- a/admin/tool/monitor/lang/en/tool_monitor.php +++ b/admin/tool/monitor/lang/en/tool_monitor.php @@ -84,7 +84,7 @@ $string['subdeletesuccess'] = "Subscription successfully removed"; $string['subhelp'] = 'Subscription details'; $string['subhelp_help'] = 'This subscription listens for when the event \'{$a->eventname}\' has been triggered in \'{$a->moduleinstance}\' {$a->frequency} time(s) in {$a->minutes} minute(s).'; $string['title'] = '{$a->coursename} : {$a->reportname}'; -$string['tool/monitor:managerules'] = 'Manage event monitor rules'; -$string['tool/monitor:subscribe'] = 'Subscribe to event monitor rules'; +$string['monitor:managerules'] = 'Manage event monitor rules'; +$string['monitor:subscribe'] = 'Subscribe to event monitor rules'; $string['unsubscribe'] = 'Unsubscribe'; From 75cae53b7b51c92212b819f298e3eb862e9b6289 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Wed, 8 Oct 2014 13:04:58 +0530 Subject: [PATCH 39/44] MDL-45758 tool_monitor: Peer review changes --- admin/tool/monitor/classes/eventlist.php | 1 + admin/tool/monitor/classes/helper_trait.php | 104 ------------------ .../classes/output/managerules/renderable.php | 6 +- .../classes/output/managesubs/subs.php | 2 +- admin/tool/monitor/classes/rule.php | 68 +++++++++++- admin/tool/monitor/classes/subscription.php | 66 ++++++++++- admin/tool/monitor/index.php | 5 +- admin/tool/monitor/lang/en/tool_monitor.php | 2 +- admin/tool/monitor/managerules.php | 1 + lib/navigationlib.php | 13 ++- 10 files changed, 149 insertions(+), 119 deletions(-) delete mode 100644 admin/tool/monitor/classes/helper_trait.php diff --git a/admin/tool/monitor/classes/eventlist.php b/admin/tool/monitor/classes/eventlist.php index b503fd8b9c7..989bc3cafa2 100644 --- a/admin/tool/monitor/classes/eventlist.php +++ b/admin/tool/monitor/classes/eventlist.php @@ -165,6 +165,7 @@ class eventlist { public static function get_all_eventlist($withoutcomponent = false) { if ($withoutcomponent) { $return = array_merge(self::get_core_eventlist(), self::get_non_core_eventlist($withoutcomponent)); + array_multisort($return, SORT_NATURAL); } else { $return = array_merge(array('core' => self::get_core_eventlist()), self::get_non_core_eventlist($withoutcomponent = false)); diff --git a/admin/tool/monitor/classes/helper_trait.php b/admin/tool/monitor/classes/helper_trait.php deleted file mode 100644 index e810a8601cf..00000000000 --- a/admin/tool/monitor/classes/helper_trait.php +++ /dev/null @@ -1,104 +0,0 @@ -. - -/** - * Common methods that are needed both in rule and subscription class. - * - * @package tool_monitor - * @copyright 2014 onwards Ankit Agarwal - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace tool_monitor; - -defined('MOODLE_INTERNAL') || die(); -require_once($CFG->dirroot . '/lib/moodlelib.php'); - -/** - * Common methods that are needed both in rule and subscription class. - * - * @since Moodle 2.8 - * @package tool_monitor - * @copyright 2014 onwards Ankit Agarwal - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -trait helper_trait { - - /** - * Method to get event name. - * - * @return string - * @throws \coding_exception - */ - public function get_event_name() { - $eventclass = $this->eventname; - if (class_exists($eventclass)) { - return $eventclass::get_name(); - } - return get_string('eventnotfound', 'tool_monitor'); - } - - /** - * Get filter description. - * - * @return string - */ - public function get_filters_description() { - $a = new \stdClass(); - $a->freq = $this->frequency; - $mins = $this->timewindow / MINSECS; // Convert seconds to minutes. - $a->mins = $mins; - return get_string('freqdesc', 'tool_monitor', $a); - } - - /** - * Get properly formatted name of the rule associated. - * - * @param \context $context context where this name would be displayed. - * - * @return string Formatted name of the rule. - */ - public function get_name(\context $context) { - return format_text($this->name, FORMAT_HTML, array('context' => $context)); - } - - /** - * Get properly formatted description of the rule associated. - * - * @param \context $context context where this description would be displayed. - * - * @return string Formatted description of the rule. - */ - public function get_description(\context $context) { - return format_text($this->description, $this->descriptionformat, array('context' => $context)); - } - - /** - * Get name of the plugin associated with this rule - * - * @return string Plugin name. - */ - public function get_plugin_name() { - if ($this->plugin === 'core') { - $string = get_string('core', 'tool_monitor'); - } else if (get_string_manager()->string_exists('pluginname', $this->plugin)) { - $string = get_string('pluginname', $this->plugin); - } else { - $string = $this->plugin; - } - return $string; - } -} diff --git a/admin/tool/monitor/classes/output/managerules/renderable.php b/admin/tool/monitor/classes/output/managerules/renderable.php index 8534d1be346..2c742450748 100644 --- a/admin/tool/monitor/classes/output/managerules/renderable.php +++ b/admin/tool/monitor/classes/output/managerules/renderable.php @@ -157,11 +157,11 @@ class renderable extends \table_sql implements \renderable { if ($this->hassystemcap || ($rule->courseid !== 0)) { // There might be site rules which the user can not manage. $editurl = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/edit.php', array('ruleid' => $rule->id, - 'courseid' => $rule->courseid)); + 'courseid' => $rule->courseid, 'sesskey' => sesskey())); $copyurl = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/managerules.php', - array('ruleid' => $rule->id, 'action' => 'copy', 'courseid' => $this->courseid)); + array('ruleid' => $rule->id, 'action' => 'copy', 'courseid' => $this->courseid, 'sesskey' => sesskey())); $deleteurl = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/managerules.php', array('ruleid' => $rule->id, - 'action' => 'delete', 'courseid' => $rule->courseid)); + 'action' => 'delete', 'courseid' => $rule->courseid, 'sesskey' => sesskey())); $icon = $OUTPUT->render(new \pix_icon('t/edit', get_string('editrule', 'tool_monitor'))); $manage .= \html_writer::link($editurl, $icon, array('class' => 'action-icon')); diff --git a/admin/tool/monitor/classes/output/managesubs/subs.php b/admin/tool/monitor/classes/output/managesubs/subs.php index 1e93786a117..bfae756b47c 100644 --- a/admin/tool/monitor/classes/output/managesubs/subs.php +++ b/admin/tool/monitor/classes/output/managesubs/subs.php @@ -124,7 +124,7 @@ class subs extends \table_sql implements \renderable { $a = $sub->get_name($this->context); $deleteurl = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/index.php', array('subscriptionid' => $sub->id, - 'action' => 'unsubscribe', 'courseid' => $this->courseid)); + 'action' => 'unsubscribe', 'courseid' => $this->courseid, 'sesskey' => sesskey())); $action = new \component_action('click', 'M.util.show_confirm_dialog', array('message' => get_string('subareyousure', 'tool_monitor', $a))); $icon = $OUTPUT->action_link($deleteurl, diff --git a/admin/tool/monitor/classes/rule.php b/admin/tool/monitor/classes/rule.php index 0aeb34f0283..81b3aef94e1 100644 --- a/admin/tool/monitor/classes/rule.php +++ b/admin/tool/monitor/classes/rule.php @@ -35,7 +35,6 @@ defined('MOODLE_INTERNAL') || die(); * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class rule { - use helper_trait; /** * @var \stdClass The rule object form database. @@ -118,7 +117,7 @@ class rule { } } $url = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/index.php', array('courseid' => $courseid, 'ruleid' => $this->id, - 'action' => 'subscribe')); + 'action' => 'subscribe', 'sesskey' => sesskey())); return new \single_select($url, 'cmid', $options, '', $nothing = array('' => 'choosedots')); } @@ -180,4 +179,69 @@ class rule { } throw new \coding_exception('Invalid call to get_mform_set_data.'); } + + /** + * Method to get event name. + * + * @return string + * @throws \coding_exception + */ + public function get_event_name() { + $eventclass = $this->eventname; + if (class_exists($eventclass)) { + return $eventclass::get_name(); + } + return get_string('eventnotfound', 'tool_monitor'); + } + + /** + * Get filter description. + * + * @return string + */ + public function get_filters_description() { + $a = new \stdClass(); + $a->freq = $this->frequency; + $mins = $this->timewindow / MINSECS; // Convert seconds to minutes. + $a->mins = $mins; + return get_string('freqdesc', 'tool_monitor', $a); + } + + /** + * Get properly formatted name of the rule associated. + * + * @param \context $context context where this name would be displayed. + * + * @return string Formatted name of the rule. + */ + public function get_name(\context $context) { + return format_text($this->name, FORMAT_HTML, array('context' => $context)); + } + + /** + * Get properly formatted description of the rule associated. + * + * @param \context $context context where this description would be displayed. + * + * @return string Formatted description of the rule. + */ + public function get_description(\context $context) { + return format_text($this->description, $this->descriptionformat, array('context' => $context)); + } + + /** + * Get name of the plugin associated with this rule + * + * @return string Plugin name. + */ + public function get_plugin_name() { + if ($this->plugin === 'core') { + $string = get_string('core', 'tool_monitor'); + } else if (get_string_manager()->string_exists('pluginname', $this->plugin)) { + $string = get_string('pluginname', $this->plugin); + } else { + $string = $this->plugin; + } + return $string; + } } diff --git a/admin/tool/monitor/classes/subscription.php b/admin/tool/monitor/classes/subscription.php index 4355e8c2d22..0665bb4a8d4 100644 --- a/admin/tool/monitor/classes/subscription.php +++ b/admin/tool/monitor/classes/subscription.php @@ -35,7 +35,6 @@ defined('MOODLE_INTERNAL') || die(); * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class subscription { - use helper_trait; /** * @var \stdClass */ @@ -93,4 +92,69 @@ class subscription { return $string; } + + /** + * Method to get event name. + * + * @return string + * @throws \coding_exception + */ + public function get_event_name() { + $eventclass = $this->eventname; + if (class_exists($eventclass)) { + return $eventclass::get_name(); + } + return get_string('eventnotfound', 'tool_monitor'); + } + + /** + * Get filter description. + * + * @return string + */ + public function get_filters_description() { + $a = new \stdClass(); + $a->freq = $this->frequency; + $mins = $this->timewindow / MINSECS; // Convert seconds to minutes. + $a->mins = $mins; + return get_string('freqdesc', 'tool_monitor', $a); + } + + /** + * Get properly formatted name of the rule associated. + * + * @param \context $context context where this name would be displayed. + * + * @return string Formatted name of the rule. + */ + public function get_name(\context $context) { + return format_text($this->name, FORMAT_HTML, array('context' => $context)); + } + + /** + * Get properly formatted description of the rule associated. + * + * @param \context $context context where this description would be displayed. + * + * @return string Formatted description of the rule. + */ + public function get_description(\context $context) { + return format_text($this->description, $this->descriptionformat, array('context' => $context)); + } + + /** + * Get name of the plugin associated with this rule + * + * @return string Plugin name. + */ + public function get_plugin_name() { + if ($this->plugin === 'core') { + $string = get_string('core', 'tool_monitor'); + } else if (get_string_manager()->string_exists('pluginname', $this->plugin)) { + $string = get_string('pluginname', $this->plugin); + } else { + $string = $this->plugin; + } + return $string; + } } diff --git a/admin/tool/monitor/index.php b/admin/tool/monitor/index.php index d2a90a57d8b..778f722c1dd 100644 --- a/admin/tool/monitor/index.php +++ b/admin/tool/monitor/index.php @@ -68,6 +68,7 @@ echo $OUTPUT->header(); // Create/delete subscription if needed. if (!empty($action)) { + require_sesskey(); switch ($action) { case 'subscribe' : $rule = \tool_monitor\rule_manager::get_rule($ruleid); @@ -104,7 +105,9 @@ if (!empty($totalrules)) { if (has_capability('tool/monitor:managerules', $context)) { $manageurl = new moodle_url("/admin/tool/monitor/managerules.php", array('courseid' => $courseid)); $a = html_writer::link($manageurl, get_string('managerules', 'tool_monitor')); - echo html_writer::tag('span', get_string('manageruleslink', 'tool_monitor', $a)); + $link = " "; + $link .= html_writer::tag('span', get_string('manageruleslink', 'tool_monitor', $a)); + echo $link; } } echo $OUTPUT->footer(); diff --git a/admin/tool/monitor/lang/en/tool_monitor.php b/admin/tool/monitor/lang/en/tool_monitor.php index 6afa1927e3c..cae3db7cc79 100644 --- a/admin/tool/monitor/lang/en/tool_monitor.php +++ b/admin/tool/monitor/lang/en/tool_monitor.php @@ -49,7 +49,7 @@ $string['moduleinstance'] = 'Module instance'; $string['manage'] = 'Manage'; $string['managesubscriptions'] = 'Manage subscriptions'; $string['managerules'] = 'Manage rules'; -$string['messageheader'] = 'Customize your notification message'; +$string['messageheader'] = 'Customise your notification message'; $string['messageprovider:notification'] = 'Notifications of rule subscriptions'; $string['messagetemplate'] = 'Message template'; $string['messagetemplate_help'] = 'This is the content of the message that will be sent to users, when the given conditions of the rule are met. You are allowed to use following templates in this. diff --git a/admin/tool/monitor/managerules.php b/admin/tool/monitor/managerules.php index ec1065919dc..8259fecf304 100644 --- a/admin/tool/monitor/managerules.php +++ b/admin/tool/monitor/managerules.php @@ -66,6 +66,7 @@ echo $OUTPUT->header(); // Copy/delete rule if needed. if (!empty($action) && $ruleid) { + require_sesskey(); $rule = \tool_monitor\rule_manager::get_rule($ruleid); if ($rule->can_manage_rule()) { switch ($action) { diff --git a/lib/navigationlib.php b/lib/navigationlib.php index 179f2471b21..53346f21b34 100644 --- a/lib/navigationlib.php +++ b/lib/navigationlib.php @@ -3773,12 +3773,6 @@ class settings_navigation extends navigation_node { } } - // Let admin tools hook into course navigation. - $tools = get_plugin_list_with_function('tool', 'extend_navigation_course', 'lib.php'); - foreach ($tools as $toolfunction) { - $toolfunction($coursenode, $course, $coursecontext); - } - // Add view grade report is permitted $reportavailable = false; if (has_capability('moodle/grade:viewall', $coursecontext)) { @@ -3897,6 +3891,13 @@ class settings_navigation extends navigation_node { $switchroles->add($name, $url, self::TYPE_SETTING, null, $key, new pix_icon('i/switchrole', '')); } } + + // Let admin tools hook into course navigation. + $tools = get_plugin_list_with_function('tool', 'extend_navigation_course', 'lib.php'); + foreach ($tools as $toolfunction) { + $toolfunction($coursenode, $course, $coursecontext); + } + // Return we are done return $coursenode; } From e8a925a60e77433b740529be5d094b026301351b Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Wed, 8 Oct 2014 15:05:35 +0530 Subject: [PATCH 40/44] MDL-45758 tool_monitor: Update js to get around chrome bug --- admin/tool/monitor/classes/rule_form.php | 2 -- admin/tool/monitor/edit.php | 15 +++++--- .../moodle-tool_monitor-dropdown-debug.js | 36 +++++++++++++------ .../moodle-tool_monitor-dropdown-min.js | 2 +- .../moodle-tool_monitor-dropdown.js | 36 +++++++++++++------ .../monitor/yui/src/dropdown/js/dropdown.js | 36 +++++++++++++------ 6 files changed, 90 insertions(+), 37 deletions(-) diff --git a/admin/tool/monitor/classes/rule_form.php b/admin/tool/monitor/classes/rule_form.php index 99b3c8de892..66d59f6eac2 100644 --- a/admin/tool/monitor/classes/rule_form.php +++ b/admin/tool/monitor/classes/rule_form.php @@ -46,8 +46,6 @@ class rule_form extends \moodleform { $pluginlist = $this->_customdata['pluginlist']; $rule = $this->_customdata['rule']; $courseid = $this->_customdata['courseid']; - $eventlist = array_merge(array('' => get_string('choosedots')), $eventlist); - $pluginlist = array_merge(array('' => get_string('choosedots')), $pluginlist); // General section header. $mform->addElement('header', 'general', get_string('general')); diff --git a/admin/tool/monitor/edit.php b/admin/tool/monitor/edit.php index 8722da35d2d..c69e92e0620 100644 --- a/admin/tool/monitor/edit.php +++ b/admin/tool/monitor/edit.php @@ -55,7 +55,16 @@ $PAGE->set_url($url); $PAGE->set_pagelayout('report'); $PAGE->set_title($title); $PAGE->set_heading($title); -$PAGE->requires->yui_module('moodle-tool_monitor-dropdown', 'Y.M.tool_monitor.DropDown.init'); + +// Get data ready for mform. +$eventlist = tool_monitor\eventlist::get_all_eventlist(true); +$pluginlist = tool_monitor\eventlist::get_plugin_list(); +$eventlist = array_merge(array('' => get_string('choosedots')), $eventlist); +$pluginlist = array_merge(array('' => get_string('choosedots')), $pluginlist); + +// Set up the yui module. +$PAGE->requires->yui_module('moodle-tool_monitor-dropdown', 'Y.M.tool_monitor.DropDown.init', + array(array('eventlist' => $eventlist))); // Site level report. if (empty($courseid)) { @@ -65,9 +74,7 @@ if (empty($courseid)) { $PAGE->navigation->override_active_url($manageurl); } -// Get data ready for mform. -$eventlist = tool_monitor\eventlist::get_all_eventlist(true); -$pluginlist = tool_monitor\eventlist::get_plugin_list(); +// Mform setup. if (!empty($ruleid)) { $rule = \tool_monitor\rule_manager::get_rule($ruleid)->get_mform_set_data(); $rule->minutes = $rule->timewindow / MINSECS; diff --git a/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-debug.js b/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-debug.js index 992c45be5b4..79184dd7bc1 100644 --- a/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-debug.js +++ b/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-debug.js @@ -66,22 +66,38 @@ Y.extend(DropDown, Y.Base, { * @method updateEventsList */ updateEventsList: function() { + var node, options, choosenode; var plugin = this.plugin.get('value'); // Get component name. var namespace = '\\' + plugin + '\\'; - this.eventname.all(SELECTORS.OPTION).hide(); // Hide all options. - this.eventname.all(SELECTORS.OPTION).each(function(node) { - // Make sure we highlight only nodes with correct namespace. - if (node.get('value').substring(0, namespace.length) === namespace) { - node.show(); - } - }); + this.eventname.all(SELECTORS.OPTION).remove(true); // Delete all nodes. + options = this.get('eventlist'); + // Mark the default choose node as visible and selected. - var choosenode = this.eventname.one(SELECTORS.CHOOSE); - choosenode.show().set('selected', 'selected'); + choosenode = Y.Node.create(''); + choosenode.set('selected', 'selected'); + this.eventname.appendChild(choosenode); + + Y.Object.each(options, function(value, key) { + // Make sure we highlight only nodes with correct namespace. + if (key.substring(0, namespace.length) === namespace) { + node = Y.Node.create(''); + this.eventname.appendChild(node); + } + }, this); + } }, { NAME: 'dropDown', - ATTRS: {} + ATTRS: { + /** + * A list of events with components. + * + * @attribute eventlist + * @default null + * @type Object + */ + eventlist: null + } }); Y.namespace('M.tool_monitor.DropDown').init = function(config) { diff --git a/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-min.js b/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-min.js index a95a95e6f06..c62a01318d7 100644 --- a/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-min.js +++ b/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-min.js @@ -1 +1 @@ -YUI.add("moodle-tool_monitor-dropdown",function(e,t){function n(){n.superclass.constructor.apply(this,arguments)}var r={PLUGIN:"#id_plugin",EVENTNAME:"#id_eventname",OPTION:"option",CHOOSE:'option[value=""]'};e.extend(n,e.Base,{plugin:null,eventname:null,initializer:function(){this.plugin=e.one(r.PLUGIN),this.eventname=e.one(r.EVENTNAME),this.plugin.on("change",this.updateEventsList,this)},updateEventsList:function(){var e=this.plugin.get("value"),t="\\"+e+"\\";this.eventname.all(r.OPTION).hide(),this.eventname.all(r.OPTION).each(function(e){e.get("value").substring(0,t.length)===t&&e.show()});var n=this.eventname.one(r.CHOOSE);n.show().set("selected","selected")}},{NAME:"dropDown",ATTRS:{}}),e.namespace("M.tool_monitor.DropDown").init=function(e){return new n(e)}},"@VERSION@",{requires:["base","event","node"]}); +YUI.add("moodle-tool_monitor-dropdown",function(e,t){function n(){n.superclass.constructor.apply(this,arguments)}var r={PLUGIN:"#id_plugin",EVENTNAME:"#id_eventname",OPTION:"option",CHOOSE:'option[value=""]'};e.extend(n,e.Base,{plugin:null,eventname:null,initializer:function(){this.plugin=e.one(r.PLUGIN),this.eventname=e.one(r.EVENTNAME),this.plugin.on("change",this.updateEventsList,this)},updateEventsList:function(){var t,n,i,s=this.plugin.get("value"),o="\\"+s+"\\";this.eventname.all(r.OPTION).remove(!0),n=this.get("eventlist"),i=e.Node.create('"),i.set("selected","selected"),this.eventname.appendChild(i),e.Object.each(n,function(n,r){r.substring(0,o.length)===o&&(t=e.Node.create('"),this.eventname.appendChild(t))},this)}},{NAME:"dropDown",ATTRS:{eventlist:null}}),e.namespace("M.tool_monitor.DropDown").init=function(e){return new n(e)}},"@VERSION@",{requires:["base","event","node"]}); diff --git a/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown.js b/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown.js index 992c45be5b4..79184dd7bc1 100644 --- a/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown.js +++ b/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown.js @@ -66,22 +66,38 @@ Y.extend(DropDown, Y.Base, { * @method updateEventsList */ updateEventsList: function() { + var node, options, choosenode; var plugin = this.plugin.get('value'); // Get component name. var namespace = '\\' + plugin + '\\'; - this.eventname.all(SELECTORS.OPTION).hide(); // Hide all options. - this.eventname.all(SELECTORS.OPTION).each(function(node) { - // Make sure we highlight only nodes with correct namespace. - if (node.get('value').substring(0, namespace.length) === namespace) { - node.show(); - } - }); + this.eventname.all(SELECTORS.OPTION).remove(true); // Delete all nodes. + options = this.get('eventlist'); + // Mark the default choose node as visible and selected. - var choosenode = this.eventname.one(SELECTORS.CHOOSE); - choosenode.show().set('selected', 'selected'); + choosenode = Y.Node.create(''); + choosenode.set('selected', 'selected'); + this.eventname.appendChild(choosenode); + + Y.Object.each(options, function(value, key) { + // Make sure we highlight only nodes with correct namespace. + if (key.substring(0, namespace.length) === namespace) { + node = Y.Node.create(''); + this.eventname.appendChild(node); + } + }, this); + } }, { NAME: 'dropDown', - ATTRS: {} + ATTRS: { + /** + * A list of events with components. + * + * @attribute eventlist + * @default null + * @type Object + */ + eventlist: null + } }); Y.namespace('M.tool_monitor.DropDown').init = function(config) { diff --git a/admin/tool/monitor/yui/src/dropdown/js/dropdown.js b/admin/tool/monitor/yui/src/dropdown/js/dropdown.js index 00a53764e49..ff839b6ec42 100644 --- a/admin/tool/monitor/yui/src/dropdown/js/dropdown.js +++ b/admin/tool/monitor/yui/src/dropdown/js/dropdown.js @@ -64,22 +64,38 @@ Y.extend(DropDown, Y.Base, { * @method updateEventsList */ updateEventsList: function() { + var node, options, choosenode; var plugin = this.plugin.get('value'); // Get component name. var namespace = '\\' + plugin + '\\'; - this.eventname.all(SELECTORS.OPTION).hide(); // Hide all options. - this.eventname.all(SELECTORS.OPTION).each(function(node) { - // Make sure we highlight only nodes with correct namespace. - if (node.get('value').substring(0, namespace.length) === namespace) { - node.show(); - } - }); + this.eventname.all(SELECTORS.OPTION).remove(true); // Delete all nodes. + options = this.get('eventlist'); + // Mark the default choose node as visible and selected. - var choosenode = this.eventname.one(SELECTORS.CHOOSE); - choosenode.show().set('selected', 'selected'); + choosenode = Y.Node.create(''); + choosenode.set('selected', 'selected'); + this.eventname.appendChild(choosenode); + + Y.Object.each(options, function(value, key) { + // Make sure we highlight only nodes with correct namespace. + if (key.substring(0, namespace.length) === namespace) { + node = Y.Node.create(''); + this.eventname.appendChild(node); + } + }, this); + } }, { NAME: 'dropDown', - ATTRS: {} + ATTRS: { + /** + * A list of events with components. + * + * @attribute eventlist + * @default null + * @type Object + */ + eventlist: null + } }); Y.namespace('M.tool_monitor.DropDown').init = function(config) { From b9ba26b22253ce3623f5ce3d211aa3a9c9ddf51b Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Mon, 13 Oct 2014 11:54:31 +0530 Subject: [PATCH 41/44] MDL-45758 tool_monitor: Update navigation to add callbacks User settings node now checks for callbacks in various admin tools --- lib/navigationlib.php | 8 +++++++- lib/upgrade.txt | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/navigationlib.php b/lib/navigationlib.php index 53346f21b34..6f8a4dcba62 100644 --- a/lib/navigationlib.php +++ b/lib/navigationlib.php @@ -4212,7 +4212,7 @@ class settings_navigation extends navigation_node { if (empty($passwordchangeurl)) { $passwordchangeurl = new moodle_url('/login/change_password.php', array('id'=>$course->id)); } - $usersetting->add(get_string("changepassword"), $passwordchangeurl, self::TYPE_SETTING); + $usersetting->add(get_string("changepassword"), $passwordchangeurl, self::TYPE_SETTING, null, 'changepassword'); } // View the roles settings @@ -4330,6 +4330,12 @@ class settings_navigation extends navigation_node { $usersetting->add(get_string('loginas'), $url, self::TYPE_SETTING); } + // Let admin tools hook into user settings navigation. + $tools = get_plugin_list_with_function('tool', 'extend_navigation_user_settings', 'lib.php'); + foreach ($tools as $toolfunction) { + $toolfunction($usersetting, $user, $usercontext, $course, $coursecontext); + } + return $usersetting; } diff --git a/lib/upgrade.txt b/lib/upgrade.txt index b1690b06dfd..47bbe27b318 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -24,6 +24,7 @@ information provided here is intended especially for developers. it must be amended. It does not apply to lib/googleapi.php. See MDL-47297 * Added an extra parameter to the function get_formatted_help_string() (default null) which is used to specify additional string parameters. +* User settings node and course node in navigation now support callbacks from admin tools. DEPRECATIONS: * completion_info->get_incomplete_criteria() is deprecated and will be removed in Moodle 3.0. From 067e9599ac920b251e2373cd61d9127db04e7132 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Mon, 13 Oct 2014 11:54:55 +0530 Subject: [PATCH 42/44] MDL-45758 tool_monitor: Update navigation nodes --- admin/tool/monitor/lang/en/tool_monitor.php | 4 +- admin/tool/monitor/lib.php | 51 +++++++++++---------- admin/tool/monitor/settings.php | 11 +---- 3 files changed, 29 insertions(+), 37 deletions(-) diff --git a/admin/tool/monitor/lang/en/tool_monitor.php b/admin/tool/monitor/lang/en/tool_monitor.php index cae3db7cc79..50ba36ecfe6 100644 --- a/admin/tool/monitor/lang/en/tool_monitor.php +++ b/admin/tool/monitor/lang/en/tool_monitor.php @@ -47,8 +47,8 @@ $string['norules'] = 'There are no rules you can subscribe to.'; $string['manageruleslink'] = 'You can manage rules from {$a} page.'; $string['moduleinstance'] = 'Module instance'; $string['manage'] = 'Manage'; -$string['managesubscriptions'] = 'Manage subscriptions'; -$string['managerules'] = 'Manage rules'; +$string['managesubscriptions'] = 'Event monitoring'; +$string['managerules'] = 'Event monitoring rules'; $string['messageheader'] = 'Customise your notification message'; $string['messageprovider:notification'] = 'Notifications of rule subscriptions'; $string['messagetemplate'] = 'Message template'; diff --git a/admin/tool/monitor/lib.php b/admin/tool/monitor/lib.php index e562f82ad4b..88d2df99601 100644 --- a/admin/tool/monitor/lib.php +++ b/admin/tool/monitor/lib.php @@ -32,36 +32,37 @@ defined('MOODLE_INTERNAL') || die; * @param context $context The context of the course */ function tool_monitor_extend_navigation_course($navigation, $course, $context) { - $node = navigation_node::create(get_string('pluginname', 'tool_monitor'), null, navigation_node::TYPE_CONTAINER, null, - 'eventmonitor', new pix_icon('i/tool', '')); if (has_capability('tool/monitor:managerules', $context)) { $url = new moodle_url('/admin/tool/monitor/managerules.php', array('courseid' => $course->id)); $settingsnode = navigation_node::create(get_string('managerules', 'tool_monitor'), $url, navigation_node::TYPE_SETTING, - null, null, new pix_icon('i/settings', '')); - } + null, null, new pix_icon('i/settings', '')); + $reportnode = $navigation->get('coursereports'); - if (has_capability('tool/monitor:subscribe', $context)) { - $url = new moodle_url('/admin/tool/monitor/index.php', array('courseid' => $course->id)); - $subsnode = navigation_node::create(get_string('managesubscriptions', 'tool_monitor'), $url, - navigation_node::TYPE_SETTING, null, null, new pix_icon('i/settings', '')); - } - - $reportnode = $navigation->get('coursereports'); - - if ((isset($subsnode) || isset($settingsnode)) && !empty($reportnode)) { - // Add the node only if there are sub pages. - $node = $reportnode->add_node($node); - - // Our navigation lib can not handle nodes that have active child, so we need to always add parent first without - // children. Refer MDL-45872 . - - if (isset($settingsnode)) { - $node->add_node($settingsnode); - } - - if (isset($subsnode)) { - $node->add_node($subsnode); + if (isset($settingsnode) && !empty($reportnode)) { + $reportnode->add_node($settingsnode); } } } + +/** + * This function extends the navigation with the tool items for user settings node. + * + * @param navigation_node $navigation The navigation node to extend + * @param stdClass $user The user object + * @param context $usercontext The context of the user + * @param stdClass $course The course to object for the tool + * @param context $coursecontext The context of the course + */ +function tool_monitor_extend_navigation_user_settings($navigation, $user, $usercontext, $course, $coursecontext) { + global $USER; + if (($USER->id == $user->id)) { + $url = new moodle_url('/admin/tool/monitor/index.php', array('courseid' => $course->id)); + $subsnode = navigation_node::create(get_string('managesubscriptions', 'tool_monitor'), $url, + navigation_node::TYPE_SETTING, null, null, new pix_icon('i/settings', '')); + + if (isset($subsnode) && !empty($navigation)) { + $navigation->add_node($subsnode, 'changepassword'); + } + } +} \ No newline at end of file diff --git a/admin/tool/monitor/settings.php b/admin/tool/monitor/settings.php index 9bfc3013dc4..9e324684191 100644 --- a/admin/tool/monitor/settings.php +++ b/admin/tool/monitor/settings.php @@ -26,19 +26,10 @@ defined('MOODLE_INTERNAL') || die; if ($hassiteconfig) { - $ADMIN->add('reports', new admin_category('toolmonitor', new lang_string('pluginname', 'tool_monitor'))); // Manage rules page. $url = new moodle_url('/admin/tool/monitor/managerules.php', array('courseid' => 0)); $temp = new admin_externalpage('toolmonitorrules', get_string('managerules', 'tool_monitor'), $url, 'tool/monitor:managerules'); - $ADMIN->add('toolmonitor', $temp); - - // Manage subscriptions page. - $url = new moodle_url('/admin/tool/monitor/index.php', array('courseid' => 0)); - $temp = new admin_externalpage('toolmonitorsubscriptions', get_string('managesubscriptions', 'tool_monitor'), $url, - 'tool/monitor:subscribe'); - $ADMIN->add('toolmonitor', $temp); - - $settings = null; + $ADMIN->add('reports', $temp); } From ffe9ed541c47cc603775e158940d158dbe709636 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Mon, 13 Oct 2014 12:46:48 +0530 Subject: [PATCH 43/44] MDL-45758 tool_monitor: Update subscriptions management UI --- .../classes/output/managesubs/renderer.php | 17 +++++++- .../classes/output/managesubs/rules.php | 25 +++++++++++ .../classes/output/managesubs/subs.php | 39 ++++++++++++++--- admin/tool/monitor/classes/rule_form.php | 4 +- admin/tool/monitor/classes/subscription.php | 32 ++++++++++++++ .../monitor/classes/subscription_manager.php | 42 ++++++++++++++++++- admin/tool/monitor/index.php | 34 +++++++-------- admin/tool/monitor/lang/en/tool_monitor.php | 9 ++-- 8 files changed, 171 insertions(+), 31 deletions(-) diff --git a/admin/tool/monitor/classes/output/managesubs/renderer.php b/admin/tool/monitor/classes/output/managesubs/renderer.php index 7d0161f258f..fe3f8e05bf8 100644 --- a/admin/tool/monitor/classes/output/managesubs/renderer.php +++ b/admin/tool/monitor/classes/output/managesubs/renderer.php @@ -56,10 +56,25 @@ class renderer extends \plugin_renderer_base { * @return string to display on the mangesubs page. */ protected function render_rules(rules $renderable) { - $o = $this->render_table($renderable); + $o = $this->render_course_select($renderable); + if (!empty($renderable->totalcount)) { + $o .= $this->render_table($renderable); + } return $o; } + /** + * Get html to display on the page for select dropdown.. + * + * @param rules $renderable renderable widget + * + * @return string to display on the mangesubs page. + */ + protected function render_course_select(rules $renderable) { + $select = $renderable->get_user_courses_select(); + return $this->render($select);; + } + /** * Get html to display on the page. * diff --git a/admin/tool/monitor/classes/output/managesubs/rules.php b/admin/tool/monitor/classes/output/managesubs/rules.php index d655a43f8e8..f891e90c1a1 100644 --- a/admin/tool/monitor/classes/output/managesubs/rules.php +++ b/admin/tool/monitor/classes/output/managesubs/rules.php @@ -43,6 +43,11 @@ class rules extends \table_sql implements \renderable { */ public $courseid; + /** + * @var int total rules present. + */ + public $totalcount = 0; + /** * @var \context_course|\context_system context of the page to be rendered. */ @@ -84,6 +89,8 @@ class rules extends \table_sql implements \renderable { $this->is_downloadable(false); $this->define_baseurl($url); $this->helpiconrenderer = $PAGE->get_renderer('tool_monitor', 'helpicon'); + $total = \tool_monitor\rule_manager::count_rules_by_courseid($this->courseid); + $this->totalcount = $total; } /** @@ -143,4 +150,22 @@ class rules extends \table_sql implements \renderable { $this->initialbars($total > $pagesize); } } + + /** + * Gets a list of courses where the current user can subscribe to rules as a dropdown. + * + * @return \single_select list of courses. + */ + public function get_user_courses_select() { + $courses = get_user_capability_course('tool/monitor:subscribe', null, true, 'fullname'); + $options = array(0 => get_string('site')); + $systemcontext = \context_system::instance(); + foreach ($courses as $course) { + $options[$course->id] = format_text($course->fullname, array('context' => $systemcontext)); + } + $url = new \moodle_url('/admin/tool/monitor/index.php'); + $select = new \single_select($url, 'courseid', $options, $this->courseid); + $select->set_label(get_string('selectacourse', 'tool_monitor')); + return $select; + } } diff --git a/admin/tool/monitor/classes/output/managesubs/subs.php b/admin/tool/monitor/classes/output/managesubs/subs.php index bfae756b47c..8ba616d52d4 100644 --- a/admin/tool/monitor/classes/output/managesubs/subs.php +++ b/admin/tool/monitor/classes/output/managesubs/subs.php @@ -67,11 +67,13 @@ class subs extends \table_sql implements \renderable { parent::__construct($uniqueid); $this->set_attribute('class', 'toolmonitor subscriptions generaltable generalbox'); - $this->define_columns(array('name', 'instance', 'unsubscribe')); + $this->define_columns(array('name', 'course', 'instance', 'unsubscribe', 'editrule')); $this->define_headers(array( get_string('name'), + get_string('course'), get_string('moduleinstance', 'tool_monitor'), - get_string('unsubscribe', 'tool_monitor') + get_string('unsubscribe', 'tool_monitor'), + get_string('editrule', 'tool_monitor') ) ); $this->courseid = $courseid; @@ -101,6 +103,17 @@ class subs extends \table_sql implements \renderable { return $name . $helpicon; } + /** + * Generate content for course column. + * + * @param \tool_monitor\subscription $sub subscription object + * + * @return string html used to display the column field. + */ + public function col_course(\tool_monitor\subscription $sub) { + return $sub->get_course_name($this->context); + } + /** * Generate content for description column. * @@ -132,6 +145,23 @@ class subs extends \table_sql implements \renderable { return $icon; } + /** + * Generate content for edit rule column. + * + * @param \tool_monitor\subscription $sub subscription object + * + * @return string html used to display the column field. + */ + public function col_editrule(\tool_monitor\subscription $sub) { + if ($sub->can_manage_rule()) { + // User can manage rule. + $editurl = new \moodle_url('/admin/tool/monitor/edit.php', array('ruleid' => $sub->ruleid, + 'courseid' => $sub->rulecourseid)); + return \html_writer::link($editurl, get_string('editrule', 'tool_monitor')); + } + return '-'; + } + /** * Query the reader. Store results in the object for use by build_table. * @@ -140,10 +170,9 @@ class subs extends \table_sql implements \renderable { */ public function query_db($pagesize, $useinitialsbar = true) { - $total = \tool_monitor\subscription_manager::count_user_subscriptions_for_course($this->courseid); + $total = \tool_monitor\subscription_manager::count_user_subscriptions(); $this->pagesize($pagesize, $total); - $subs = \tool_monitor\subscription_manager::get_user_subscriptions_for_course($this->courseid, $this->get_page_start(), - $this->get_page_size()); + $subs = \tool_monitor\subscription_manager::get_user_subscriptions($this->get_page_start(), $this->get_page_size()); $this->rawdata = $subs; // Set initial bars. if ($useinitialsbar) { diff --git a/admin/tool/monitor/classes/rule_form.php b/admin/tool/monitor/classes/rule_form.php index 66d59f6eac2..a06977948a9 100644 --- a/admin/tool/monitor/classes/rule_form.php +++ b/admin/tool/monitor/classes/rule_form.php @@ -105,7 +105,7 @@ class rule_form extends \moodleform { $mform->addHelpButton('description', 'description', 'tool_monitor'); // Filters. - $mform->addElement('header', 'customizefilters', get_string('customizefilters', 'tool_monitor')); + $mform->addElement('header', 'customisefilters', get_string('customisefilters', 'tool_monitor')); $freq = array(1 => 1, 5 => 5, 10 => 10, 20 => 20, 30 => 30, 40 => 40, 50 => 50, 60 => 60, 70 => 70, 80 => 80, 90 => 90, 100 => 100, 1000 => 1000); $mform->addElement('select', 'frequency', get_string('selectfrequency', 'tool_monitor'), $freq); @@ -118,7 +118,7 @@ class rule_form extends \moodleform { $mform->addRule('minutes', get_string('required'), 'required'); // Message template. - $mform->addElement('header', 'customizemessage', get_string('customizemessage', 'tool_monitor')); + $mform->addElement('header', 'customisemessage', get_string('customisemessage', 'tool_monitor')); $mform->addElement('editor', 'template', get_string('messagetemplate', 'tool_monitor'), $editoroptions); $mform->setDefault('template', get_string('defaultmessagetpl', 'tool_monitor')); $mform->addRule('template', get_string('required'), 'required'); diff --git a/admin/tool/monitor/classes/subscription.php b/admin/tool/monitor/classes/subscription.php index 0665bb4a8d4..a729dc85469 100644 --- a/admin/tool/monitor/classes/subscription.php +++ b/admin/tool/monitor/classes/subscription.php @@ -157,4 +157,36 @@ class subscription { } return $string; } + + /** + * Get properly formatted name of the course associated. + * + * @param \context $context context where this name would be displayed. + * + * @return string Formatted name of the rule. + */ + public function get_course_name(\context $context) { + global $SITE; + $courseid = $this->courseid; + if (empty($courseid)) { + $coursename = format_string($SITE->fullname, true, array('context' => $context)); + } else { + $course = get_course($this->courseid); + $link = new \moodle_url('/course/view.php', array('id' => $course->id)); + $coursename = format_string($course->fullname, true, array('context' => $context)); + $coursename = \html_writer::link($link, $coursename); + } + return $coursename; + } + + /** + * Can the current user manage the rule associate with this subscription? + * + * @return bool true if the current user can manage this rule, else false. + */ + public function can_manage_rule() { + $courseid = $this->rulecourseid; + $context = empty($courseid) ? \context_system::instance() : \context_course::instance($courseid); + return has_capability('tool/monitor:managerules', $context); + } } diff --git a/admin/tool/monitor/classes/subscription_manager.php b/admin/tool/monitor/classes/subscription_manager.php index 3d4d0f3561c..82796a34189 100644 --- a/admin/tool/monitor/classes/subscription_manager.php +++ b/admin/tool/monitor/classes/subscription_manager.php @@ -170,7 +170,7 @@ class subscription_manager { * @param int $courseid course id. * @param int $userid Id of the user for which the subscription needs to be fetched. Defaults to $USER; * - * @return array list of subscriptions + * @return int number of subscriptions */ public static function count_user_subscriptions_for_course($courseid, $userid = 0) { global $DB, $USER; @@ -183,6 +183,46 @@ class subscription_manager { return $DB->count_records_sql($sql, array('courseid' => $courseid, 'userid' => $userid)); } + /** + * Get an array of subscriptions for a given user. + * + * @param int $limitfrom Limit from which to fetch rules. + * @param int $limitto Limit to which rules need to be fetched. + * @param int $userid Id of the user for which the subscription needs to be fetched. Defaults to $USER; + * @param string $order Order to sort the subscriptions. + * + * @return array list of subscriptions + */ + public static function get_user_subscriptions($limitfrom = 0, $limitto = 0, $userid = 0, + $order = 's.timecreated DESC' ) { + global $DB, $USER; + if ($userid == 0) { + $userid = $USER->id; + } + $sql = self::get_subscription_join_rule_sql(); + $sql .= "WHERE s.userid = :userid ORDER BY $order"; + + return self::get_instances($DB->get_records_sql($sql, array('userid' => $userid), $limitfrom, $limitto)); + } + + /** + * Get count of subscriptions for a given user. + * + * @param int $userid Id of the user for which the subscription needs to be fetched. Defaults to $USER; + * + * @return int number of subscriptions + */ + public static function count_user_subscriptions($userid = 0) { + global $DB, $USER;; + if ($userid == 0) { + $userid = $USER->id; + } + $sql = self::get_subscription_join_rule_sql(true); + $sql .= "WHERE s.userid = :userid"; + + return $DB->count_records_sql($sql, array('userid' => $userid)); + } + /** * Return a list of subscriptions for a given event. * diff --git a/admin/tool/monitor/index.php b/admin/tool/monitor/index.php index 778f722c1dd..45c7309b6c6 100644 --- a/admin/tool/monitor/index.php +++ b/admin/tool/monitor/index.php @@ -34,22 +34,24 @@ $subscriptionid = optional_param('subscriptionid', 0, PARAM_INT); // Validate course id. if (empty($courseid)) { require_login(); - $context = context_system::instance(); - $coursename = format_string($SITE->fullname, true, array('context' => $context)); - $PAGE->set_context($context); } else { + // They might want to see rules for this course. $course = get_course($courseid); require_login($course); - $context = context_course::instance($course->id); - $coursename = format_string($course->fullname, true, array('context' => $context)); + $coursecontext = context_course::instance($course->id); + // Check for caps. + require_capability('tool/monitor:subscribe', $coursecontext); + $coursename = format_string($course->fullname, true, array('context' => $coursecontext)); } -// Check for caps. -require_capability('tool/monitor:subscribe', $context); +// Always build the page in site context. +$context = context_system::instance(); +$sitename = format_string($SITE->fullname, true, array('context' => $context)); +$PAGE->set_context($context); // Set up the page. $a = new stdClass(); -$a->coursename = $coursename; +$a->coursename = $sitename; $a->reportname = get_string('pluginname', 'tool_monitor'); $title = get_string('title', 'tool_monitor', $a); $indexurl = new moodle_url("/admin/tool/monitor/index.php", array('courseid' => $courseid)); @@ -59,11 +61,6 @@ $PAGE->set_pagelayout('report'); $PAGE->set_title($title); $PAGE->set_heading($title); -// Site level report. -if (empty($courseid)) { - admin_externalpage_setup('toolmonitorsubscriptions', '', null, '', array('pagelayout' => 'report')); -} - echo $OUTPUT->header(); // Create/delete subscription if needed. @@ -84,7 +81,7 @@ if (!empty($action)) { } // Render the current subscriptions list. -$totalsubs = \tool_monitor\subscription_manager::count_user_subscriptions_for_course($courseid); +$totalsubs = \tool_monitor\subscription_manager::count_user_subscriptions(); $renderer = $PAGE->get_renderer('tool_monitor', 'managesubs'); if (!empty($totalsubs)) { // Show the subscriptions section only if there are subscriptions. @@ -96,11 +93,11 @@ if (!empty($totalsubs)) { // Render the potential rules list. $totalrules = \tool_monitor\rule_manager::count_rules_by_courseid($courseid); echo $OUTPUT->heading(get_string('rulescansubscribe', 'tool_monitor')); -if (!empty($totalrules)) { - $rules = new \tool_monitor\output\managesubs\rules('toolmonitorrules', $indexurl, $courseid); - echo $renderer->render($rules); -} else { +$rules = new \tool_monitor\output\managesubs\rules('toolmonitorrules', $indexurl, $courseid); +echo $renderer->render($rules); +if (empty($totalrules)) { // No rules present. Show a link to manage rules page if permissions permit. + echo html_writer::start_div(); echo html_writer::tag('span', get_string('norules', 'tool_monitor')); if (has_capability('tool/monitor:managerules', $context)) { $manageurl = new moodle_url("/admin/tool/monitor/managerules.php", array('courseid' => $courseid)); @@ -109,5 +106,6 @@ if (!empty($totalrules)) { $link .= html_writer::tag('span', get_string('manageruleslink', 'tool_monitor', $a)); echo $link; } + echo html_writer::end_div(); } echo $OUTPUT->footer(); diff --git a/admin/tool/monitor/lang/en/tool_monitor.php b/admin/tool/monitor/lang/en/tool_monitor.php index 50ba36ecfe6..8547f8db73c 100644 --- a/admin/tool/monitor/lang/en/tool_monitor.php +++ b/admin/tool/monitor/lang/en/tool_monitor.php @@ -28,8 +28,8 @@ $string['addrule'] = 'Add a new rule'; $string['allevents'] = 'All events'; $string['allmodules'] = 'All modules'; $string['core'] = 'Core'; -$string['customizefilters'] = 'Select the frequency of the events'; -$string['customizemessage'] = 'Cutomize the notification message'; +$string['customisefilters'] = 'Select the frequency of the events'; +$string['customisemessage'] = 'Customise the notification message'; $string['currentsubscriptions'] = 'Your current subscriptions'; $string['description_help'] = "Description is displayed to users when they want to subscribe to this rule. This helps them understand what the rule is about."; $string['defaultmessagetpl'] = 'Rule "{rulename}" has happened. You can find further details at {link}'; @@ -70,14 +70,15 @@ $string['rulehelp'] = 'Rule details'; $string['rulehelp_help'] = 'This rule listens for when the event \'{$a->eventname}\' in \'{$a->eventcomponent}\' has been triggered {$a->frequency} time(s) in {$a->minutes} minute(s).'; $string['rulenopermissions'] = 'You do not have permissions to "{$a} a rule"'; $string['rulescansubscribe'] = 'Rules you can subscribe to'; +$string['selectacourse'] = 'Select a course'; $string['selectcourse'] = 'Visit this report at course level to get a list of possible modules'; $string['selectevent'] = 'Select an event:'; -$string['selectevent_help'] = "Select an event to monitor."; +$string['selectevent_help'] = "Select an event to monitor. Please note that certain event can happen only at certain given context. For example, a rule based on 'course created' event inside a course can never be triggered."; $string['selectfrequency'] = 'Frequency of events:'; $string['selectfrequency_help'] = "Frequency defines the denisty of the event occurrence. Select criterias to define how frequently the event should happen to trigger the notification."; $string['selectminutes'] = 'in minutes:'; $string['selectplugin'] = 'Select the plugin type:'; -$string['selectplugin_help'] = "Select a plugin that you are interested in monitoring."; +$string['selectplugin_help'] = "Select a plugin that you are interested in monitoring. The event list below would be updated to display events from the selected plugin."; $string['subareyousure'] = 'Are you sure you want to delete this subscription for the rule "{$a}"?'; $string['subcreatesuccess'] = "Subscription successfully created"; $string['subdeletesuccess'] = "Subscription successfully removed"; From d6e0e275dd879caa5f6c3c629b38938c6843ea4e Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Wed, 15 Oct 2014 11:33:09 +0530 Subject: [PATCH 44/44] MDL-45758 tool_monitor: Update behat tests --- admin/tool/monitor/tests/behat/rule.feature | 22 +++++++++---------- .../monitor/tests/behat/subscription.feature | 22 ++++++++++++------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/admin/tool/monitor/tests/behat/rule.feature b/admin/tool/monitor/tests/behat/rule.feature index 3e236fa7a10..80f74d3842d 100644 --- a/admin/tool/monitor/tests/behat/rule.feature +++ b/admin/tool/monitor/tests/behat/rule.feature @@ -1,4 +1,4 @@ -@javascript @tool @tool_monitor @tool_monitor_rule +@javascript @tool @tool_monitor @tool_monitor_rules Feature: tool_monitor_rule In order to manage rules As an admin @@ -16,7 +16,7 @@ Feature: tool_monitor_rule | teacher1 | C1 | editingteacher | And I log in as "admin" And I follow "Course 1" - And I navigate to "Manage rules" node in "Course administration > Reports > Event monitor" + And I navigate to "Event monitoring rules" node in "Course administration > Reports" And I press "Add a new rule" And I set the following fields to these values: | name | New rule course level | @@ -27,7 +27,7 @@ Feature: tool_monitor_rule | minutes | 1 | | Message template | The forum post was created. {modulelink} | And I press "Save changes" - And I navigate to "Manage rules" node in "Site administration > Reports > Event monitor" + And I navigate to "Event monitoring rules" node in "Site administration > Reports" And I press "Add a new rule" And I set the following fields to these values: | name | New rule site level | @@ -44,7 +44,7 @@ Feature: tool_monitor_rule Given I log in as "teacher1" And I am on homepage And I follow "Course 1" - And I navigate to "Manage rules" node in "Course administration > Reports > Event monitor" + And I navigate to "Event monitoring rules" node in "Course administration > Reports" When I press "Add a new rule" And I set the following fields to these values: | name | New rule | @@ -64,7 +64,7 @@ Feature: tool_monitor_rule Scenario: Delete a rule on course level Given I log in as "teacher1" And I follow "Course 1" - And I navigate to "Manage rules" node in "Course administration > Reports > Event monitor" + And I navigate to "Event monitoring rules" node in "Course administration > Reports" When I click on "Delete rule" "link" Then I should see "Are you sure you want to delete rule \"New rule course level\"?" And I press "Yes" @@ -74,7 +74,7 @@ Feature: tool_monitor_rule Scenario: Edit a rule on course level Given I log in as "teacher1" And I follow "Course 1" - And I navigate to "Manage rules" node in "Course administration > Reports > Event monitor" + And I navigate to "Event monitoring rules" node in "Course administration > Reports" When I click on "Edit rule" "link" And I set the following fields to these values: | name | New rule quiz | @@ -93,7 +93,7 @@ Feature: tool_monitor_rule Scenario: Duplicate a rule on course level Given I log in as "teacher1" And I follow "Course 1" - And I navigate to "Manage rules" node in "Course administration > Reports > Event monitor" + And I navigate to "Event monitoring rules" node in "Course administration > Reports" When I click on "Duplicate rule" "link" Then I should see "Rule successfully duplicated" And "#toolmonitorrules_r1" "css_element" should appear before "#toolmonitorrules_r2" "css_element" @@ -105,7 +105,7 @@ Feature: tool_monitor_rule Scenario: Add a rule on site level Given I log in as "admin" - And I navigate to "Manage rules" node in "Site administration > Reports > Event monitor" + And I navigate to "Event monitoring rules" node in "Site administration > Reports" When I press "Add a new rule" And I set the following fields to these values: | name | New rule | @@ -124,7 +124,7 @@ Feature: tool_monitor_rule Scenario: Delete a rule on site level Given I log in as "admin" - And I navigate to "Manage rules" node in "Site administration > Reports > Event monitor" + And I navigate to "Event monitoring rules" node in "Site administration > Reports" When I click on "Delete rule" "link" Then I should see "Are you sure you want to delete rule \"New rule site level\"?" And I press "Yes" @@ -133,7 +133,7 @@ Feature: tool_monitor_rule Scenario: Edit a rule on site level Given I log in as "admin" - And I navigate to "Manage rules" node in "Site administration > Reports > Event monitor" + And I navigate to "Event monitoring rules" node in "Site administration > Reports" When I click on "Edit rule" "link" And I set the following fields to these values: | name | New Rule Quiz | @@ -151,7 +151,7 @@ Feature: tool_monitor_rule Scenario: Duplicate a rule on site level Given I log in as "admin" - And I navigate to "Manage rules" node in "Site administration > Reports > Event monitor" + And I navigate to "Event monitoring rules" node in "Site administration > Reports" When I click on "Duplicate rule" "link" Then I should see "Rule successfully duplicated" And "#toolmonitorrules_r2" "css_element" should appear after "#toolmonitorrules_r1" "css_element" diff --git a/admin/tool/monitor/tests/behat/subscription.feature b/admin/tool/monitor/tests/behat/subscription.feature index 7f77bad73e8..8d78a0a5e14 100644 --- a/admin/tool/monitor/tests/behat/subscription.feature +++ b/admin/tool/monitor/tests/behat/subscription.feature @@ -16,7 +16,7 @@ Feature: tool_monitor_subscriptions | teacher1 | C1 | editingteacher | And I log in as "admin" And I follow "Course 1" - And I navigate to "Manage rules" node in "Course administration > Reports > Event monitor" + And I navigate to "Event monitoring rules" node in "Course administration > Reports" And I press "Add a new rule" And I set the following fields to these values: | name | New rule course level | @@ -27,7 +27,7 @@ Feature: tool_monitor_subscriptions | minutes | 1 | | Message template | The course was viewed. {modulelink} | And I press "Save changes" - And I navigate to "Manage rules" node in "Site administration > Reports > Event monitor" + And I navigate to "Event monitoring rules" node in "Site administration > Reports" And I press "Add a new rule" And I set the following fields to these values: | name | New rule site level | @@ -43,7 +43,8 @@ Feature: tool_monitor_subscriptions Scenario: Subscribe to a rule on course level Given I log in as "teacher1" And I follow "Course 1" - And I navigate to "Manage subscriptions" node in "Course administration > Reports > Event monitor" + And I navigate to "Event monitoring" node in "My profile settings" + And I set the field "courseid" to "Course 1" When I set the field "cmid" to "All events" Then I should see "Subscription successfully created" And "#toolmonitorsubs_r0" "css_element" should exist @@ -51,7 +52,8 @@ Feature: tool_monitor_subscriptions Scenario: Delete a subscription on course level Given I log in as "teacher1" And I follow "Course 1" - And I navigate to "Manage subscriptions" node in "Course administration > Reports > Event monitor" + And I navigate to "Event monitoring" node in "My profile settings" + And I set the field "courseid" to "Course 1" And I set the field "cmid" to "All events" And I should see "Subscription successfully created" When I click on "Delete subscription" "link" @@ -62,14 +64,16 @@ Feature: tool_monitor_subscriptions Scenario: Subscribe to a rule on site level Given I log in as "admin" - And I navigate to "Manage subscriptions" node in "Site administration > Reports > Event monitor" + And I navigate to "Event monitoring" node in "My profile settings" + And I set the field "courseid" to "Site" When I set the field "cmid" to "All events" Then I should see "Subscription successfully created" And "#toolmonitorsubs_r0" "css_element" should exist Scenario: Delete a subscription on site level Given I log in as "admin" - And I navigate to "Manage subscriptions" node in "Site administration > Reports > Event monitor" + And I navigate to "Event monitoring" node in "My profile settings" + And I set the field "courseid" to "Site" And I set the field "cmid" to "All events" And I should see "Subscription successfully created" And "#toolmonitorsubs_r0" "css_element" should exist @@ -86,7 +90,8 @@ Feature: tool_monitor_subscriptions And I press "Update profile" And I am on homepage And I follow "Course 1" - And I navigate to "Manage subscriptions" node in "Site administration > Reports > Event monitor" + And I navigate to "Event monitoring" node in "My profile settings" + And I set the field "courseid" to "Site" And I set the field "cmid" to "All events" And I should see "Subscription successfully created" And "#toolmonitorsubs_r0" "css_element" should exist @@ -105,7 +110,8 @@ Feature: tool_monitor_subscriptions And I press "Update profile" And I am on homepage And I follow "Course 1" - And I navigate to "Manage subscriptions" node in "Course administration > Reports > Event monitor" + And I navigate to "Event monitoring" node in "My profile settings" + And I set the field "courseid" to "Course 1" And I set the field "cmid" to "All events" And I should see "Subscription successfully created" And "#toolmonitorsubs_r0" "css_element" should exist