Merge branch 'MDL-47806' of github.com:mr-russ/moodle
authorDamyon Wiese <damyon@moodle.com>
Tue, 4 Nov 2014 06:34:43 +0000 (14:34 +0800)
committerDamyon Wiese <damyon@moodle.com>
Tue, 4 Nov 2014 06:34:43 +0000 (14:34 +0800)
359 files changed:
admin/settings/appearance.php
admin/settings/grades.php
admin/tool/installaddon/lang/en/tool_installaddon.php
admin/tool/langimport/classes/event/langpack_imported.php
admin/tool/langimport/classes/event/langpack_removed.php
admin/tool/langimport/classes/event/langpack_updated.php
admin/tool/messageinbound/classes/edit_handler_form.php
admin/tool/monitor/classes/event/rule_created.php [new file with mode: 0644]
admin/tool/monitor/classes/event/rule_deleted.php [new file with mode: 0644]
admin/tool/monitor/classes/event/rule_updated.php [new file with mode: 0644]
admin/tool/monitor/classes/event/subscription_created.php [new file with mode: 0644]
admin/tool/monitor/classes/event/subscription_criteria_met.php [new file with mode: 0644]
admin/tool/monitor/classes/event/subscription_deleted.php [new file with mode: 0644]
admin/tool/monitor/classes/eventobservers.php
admin/tool/monitor/classes/notification_task.php
admin/tool/monitor/classes/output/helpicon/renderable.php [deleted file]
admin/tool/monitor/classes/output/helpicon/renderer.php [deleted file]
admin/tool/monitor/classes/output/managerules/renderable.php
admin/tool/monitor/classes/output/managerules/renderer.php
admin/tool/monitor/classes/output/managesubs/renderer.php
admin/tool/monitor/classes/output/managesubs/rules.php
admin/tool/monitor/classes/output/managesubs/subs.php
admin/tool/monitor/classes/rule.php
admin/tool/monitor/classes/rule_form.php
admin/tool/monitor/classes/rule_manager.php
admin/tool/monitor/classes/subscription.php
admin/tool/monitor/classes/subscription_manager.php
admin/tool/monitor/classes/task/clean_events.php [new file with mode: 0644]
admin/tool/monitor/db/install.xml
admin/tool/monitor/db/tasks.php [new file with mode: 0644]
admin/tool/monitor/db/upgrade.php [new file with mode: 0644]
admin/tool/monitor/edit.php
admin/tool/monitor/help.php [deleted file]
admin/tool/monitor/help_ajax.php [deleted file]
admin/tool/monitor/index.php
admin/tool/monitor/lang/en/tool_monitor.php
admin/tool/monitor/lib.php
admin/tool/monitor/managerules.php
admin/tool/monitor/settings.php
admin/tool/monitor/tests/behat/rule.feature
admin/tool/monitor/tests/behat/subscription.feature
admin/tool/monitor/tests/eventobservers_test.php
admin/tool/monitor/tests/events_test.php [new file with mode: 0644]
admin/tool/monitor/tests/rule_manager_test.php
admin/tool/monitor/tests/subscription_manager_test.php [new file with mode: 0644]
admin/tool/monitor/tests/task_clean_events_test.php [new file with mode: 0644]
admin/tool/monitor/version.php
admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-debug.js
admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-min.js
admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown.js
admin/tool/monitor/yui/src/dropdown/js/dropdown.js
admin/tool/uploadcourse/tests/course_test.php
admin/tool/uploadcourse/tests/processor_test.php
admin/user/lib.php
auth/db/tests/db_test.php
auth/manual/auth.php
auth/tests/behat/behat_auth.php
availability/condition/profile/tests/condition_test.php
backup/cc/cc2moodle.php
backup/converter/moodle1/handlerlib.php
backup/moodle2/backup_stepslib.php
backup/moodle2/restore_stepslib.php
backup/moodle2/tests/moodle2_test.php
badges/award.php
badges/criteria/award_criteria_manual.php
badges/tests/behat/award_badge.feature
blocks/recent_activity/block_recent_activity.php
blocks/site_main_menu/block_site_main_menu.php
blocks/social_activities/block_social_activities.php
cache/stores/memcached/lib.php
cache/stores/mongodb/lib.php
calendar/lib.php
calendar/renderer.php
course/format/singleactivity/lib.php
course/mod.php
course/modduplicate.php
course/moodleform_mod.php
course/renderer.php
course/rest.php
course/tests/courselib_test.php
course/tests/externallib_test.php
course/view.php
enrol/database/tests/sync_test.php
grade/edit/letter/edit_form.php
grade/edit/letter/index.php
grade/edit/settings/form.php
grade/edit/tree/category_form.php
grade/edit/tree/item_form.php
grade/edit/tree/lib.php
grade/edit/tree/outcomeitem_form.php
grade/grading/form/guide/lib.php
grade/import/xml/import.php
grade/import/xml/lang/en/gradeimport_xml.php
grade/lib.php
grade/querylib.php
grade/report/grader/index.php
grade/report/grader/lib.php
grade/report/grader/yui/build/moodle-gradereport_grader-gradereporttable/moodle-gradereport_grader-gradereporttable-debug.js
grade/report/grader/yui/build/moodle-gradereport_grader-gradereporttable/moodle-gradereport_grader-gradereporttable-min.js
grade/report/grader/yui/build/moodle-gradereport_grader-gradereporttable/moodle-gradereport_grader-gradereporttable.js
grade/report/grader/yui/src/gradereporttable/js/floatingheaders.js
grade/report/history/classes/output/tablelog.php
grade/report/history/index.php
grade/report/history/yui/build/moodle-gradereport_history-userselector/moodle-gradereport_history-userselector-debug.js
grade/report/history/yui/build/moodle-gradereport_history-userselector/moodle-gradereport_history-userselector-min.js
grade/report/history/yui/build/moodle-gradereport_history-userselector/moodle-gradereport_history-userselector.js
grade/report/history/yui/src/userselector/js/userselector.js
grade/report/lib.php
grade/report/overview/classes/event/grade_report_viewed.php
grade/report/singleview/classes/local/screen/grade.php
grade/report/singleview/classes/local/screen/tablelike.php
grade/report/singleview/classes/local/screen/user.php
grade/report/singleview/classes/local/ui/finalgrade.php
grade/report/singleview/lang/en/gradereport_singleview.php
grade/report/singleview/styles.css
grade/report/singleview/tests/behat/singleview.feature
grade/report/user/classes/event/grade_report_viewed.php
grade/report/user/lib.php
grade/tests/behat/behat_grade.php
grade/tests/behat/grade_aggregation.feature
grade/tests/behat/grade_calculated_weights.feature
grade/tests/behat/grade_contribution_with_extra_credit.feature [new file with mode: 0644]
grade/tests/behat/grade_mingrade.feature
grade/tests/behat/grade_natural_normalisation.feature
grade/tests/behat/grade_scales.feature
grade/tests/behat/grade_scales_aggregation.feature [new file with mode: 0644]
grade/tests/behat/grade_single_item_scales.feature
grade/tests/report_graderlib_test.php
group/assign.php
install/lang/hr/moodle.php
install/lang/no/error.php
install/lang/no/install.php
install/lang/ru/error.php
iplookup/index.php
lang/en/admin.php
lang/en/grades.php
lang/en/moodle.php
lang/en/question.php
lang/en/rating.php
lib/accesslib.php
lib/adminlib.php
lib/badgeslib.php
lib/classes/event/calendar_event_updated.php
lib/classes/event/grade_report_viewed.php
lib/classes/grades_external.php
lib/classes/message/inbound/handler.php
lib/classes/task/manager.php
lib/db/install.xml
lib/db/services.php
lib/db/upgrade.php
lib/dml/mysqli_native_moodle_database.php
lib/dmllib.php
lib/editor/atto/plugins/accessibilitychecker/tests/behat/accessibilitychecker.feature
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js
lib/editor/atto/yui/src/editor/js/autosave.js
lib/filelib.php
lib/form/modgrade.php
lib/form/yui/build/moodle-form-dateselector/moodle-form-dateselector-debug.js
lib/form/yui/build/moodle-form-dateselector/moodle-form-dateselector-min.js
lib/form/yui/build/moodle-form-dateselector/moodle-form-dateselector.js
lib/form/yui/src/dateselector/js/calendar.js
lib/formslib.php
lib/grade/grade_category.php
lib/grade/grade_grade.php
lib/grade/grade_item.php
lib/grade/tests/fixtures/lib.php
lib/grade/tests/grade_item_test.php
lib/gradelib.php
lib/modinfolib.php
lib/moodlelib.php
lib/navigationlib.php
lib/outputrenderers.php
lib/phpunit/bootstrap.php
lib/setup.php
lib/setuplib.php
lib/testing/classes/util.php
lib/tests/admintree_test.php
lib/tests/behat/behat_general.php
lib/tests/behat/behat_hooks.php
lib/tests/event_user_graded_test.php
lib/tests/formslib_test.php
lib/tests/grades_externallib_test.php
lib/tests/questionlib_test.php
lib/tests/scheduled_task_test.php
lib/tests/setuplib_test.php
lib/tests/upgradelib_test.php
lib/upgrade.txt
lib/upgradelib.php
lib/weblib.php
lib/wordlist.txt
lib/yui/build/moodle-core-dock/moodle-core-dock-debug.js
lib/yui/build/moodle-core-dock/moodle-core-dock-min.js
lib/yui/build/moodle-core-dock/moodle-core-dock.js
lib/yui/build/moodle-core-dragdrop/moodle-core-dragdrop-debug.js
lib/yui/build/moodle-core-dragdrop/moodle-core-dragdrop-min.js
lib/yui/build/moodle-core-dragdrop/moodle-core-dragdrop.js
lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-debug.js
lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-min.js
lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue.js
lib/yui/src/dock/js/dock.js
lib/yui/src/dragdrop/js/dragdrop.js
lib/yui/src/notification/js/dialogue.js
message/output/airnotifier/message_output_airnotifier.php
message/tests/behat/behat_message.php
message/tests/behat/block_users.feature
message/tests/behat/display_history.feature
message/tests/behat/manage_contacts.feature
message/tests/behat/message_participants.feature
message/tests/behat/search_history.feature
mod/assign/feedback/editpdf/classes/page_editor.php
mod/assign/feedback/editpdf/tests/behat/annotate_pdf.feature
mod/assign/feedback/editpdf/tests/editpdf_test.php
mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-debug.js
mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-min.js
mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor.js
mod/assign/feedback/editpdf/yui/src/editor/js/editor.js
mod/assign/feedback/editpdf/yui/src/editor/meta/editor.json
mod/assign/locallib.php
mod/assign/tests/locallib_test.php
mod/choice/lang/en/choice.php
mod/choice/mod_form.php
mod/data/edit.php
mod/data/view.php
mod/feedback/mapcourse.php
mod/forum/classes/event/subscription_created.php
mod/forum/classes/event/subscription_deleted.php
mod/forum/classes/post_form.php
mod/forum/classes/subscriptions.php
mod/forum/db/install.xml
mod/forum/db/upgrade.php
mod/forum/discuss.php
mod/forum/externallib.php
mod/forum/index.php
mod/forum/lang/en/forum.php
mod/forum/lib.php
mod/forum/post.php
mod/forum/styles.css
mod/forum/subscribe.php
mod/forum/subscribe_ajax.php
mod/forum/tests/behat/discussion_subscriptions.feature
mod/forum/tests/behat/forum_subscriptions.feature
mod/forum/tests/behat/my_forum_posts.feature [new file with mode: 0644]
mod/forum/tests/events_test.php
mod/forum/tests/externallib_test.php
mod/forum/tests/mail_test.php
mod/forum/tests/maildigest_test.php
mod/forum/tests/subscriptions_test.php
mod/forum/unsubscribeall.php
mod/forum/version.php
mod/forum/yui/build/moodle-mod_forum-subscriptiontoggle/moodle-mod_forum-subscriptiontoggle-debug.js
mod/forum/yui/build/moodle-mod_forum-subscriptiontoggle/moodle-mod_forum-subscriptiontoggle-min.js
mod/forum/yui/build/moodle-mod_forum-subscriptiontoggle/moodle-mod_forum-subscriptiontoggle.js
mod/forum/yui/src/subscriptiontoggle/js/toggle.js
mod/glossary/index.php
mod/lesson/db/access.php
mod/lesson/essay.php
mod/lesson/lang/en/lesson.php
mod/lesson/lib.php
mod/lesson/renderer.php
mod/lesson/tabs.php
mod/lesson/tests/behat/lesson_informations_at_end.feature [new file with mode: 0644]
mod/lesson/tests/behat/teacher_grade_essays.feature [new file with mode: 0644]
mod/lesson/version.php
mod/lti/db/upgradelib.php
mod/lti/instructor_edit_tool_type.php
mod/lti/launch.php
mod/lti/locallib.php
mod/lti/registration.php
mod/lti/registrationreturn.php
mod/lti/request_tool.php
mod/lti/return.php
mod/quiz/attemptlib.php
mod/quiz/classes/output/edit_renderer.php
mod/quiz/classes/structure.php
mod/quiz/db/events.php
mod/quiz/edit.php
mod/quiz/edit_rest.php
mod/quiz/lang/en/quiz.php
mod/quiz/locallib.php
mod/quiz/module.js
mod/quiz/repaginate.php
mod/quiz/report/responses/first_or_all_responses_table.php
mod/quiz/styles.css
mod/quiz/tests/attempt_walkthrough_test.php
mod/quiz/tests/behat/behat_mod_quiz.php
mod/quiz/tests/behat/editing_click_delete_icon.feature [new file with mode: 0644]
mod/quiz/tests/generator/lib.php
mod/quiz/tests/repaginate_test.php
mod/quiz/tests/structure_test.php
mod/quiz/upgrade.txt
mod/quiz/version.php
mod/quiz/yui/build/moodle-mod_quiz-dragdrop/moodle-mod_quiz-dragdrop-debug.js
mod/quiz/yui/build/moodle-mod_quiz-dragdrop/moodle-mod_quiz-dragdrop-min.js
mod/quiz/yui/build/moodle-mod_quiz-dragdrop/moodle-mod_quiz-dragdrop.js
mod/quiz/yui/build/moodle-mod_quiz-quizbase/moodle-mod_quiz-quizbase-debug.js
mod/quiz/yui/build/moodle-mod_quiz-quizbase/moodle-mod_quiz-quizbase.js
mod/quiz/yui/build/moodle-mod_quiz-toolboxes/moodle-mod_quiz-toolboxes-debug.js
mod/quiz/yui/build/moodle-mod_quiz-toolboxes/moodle-mod_quiz-toolboxes-min.js
mod/quiz/yui/build/moodle-mod_quiz-toolboxes/moodle-mod_quiz-toolboxes.js
mod/quiz/yui/build/moodle-mod_quiz-util-page/moodle-mod_quiz-util-page-debug.js
mod/quiz/yui/build/moodle-mod_quiz-util-page/moodle-mod_quiz-util-page-min.js
mod/quiz/yui/build/moodle-mod_quiz-util-page/moodle-mod_quiz-util-page.js
mod/quiz/yui/build/moodle-mod_quiz-util-slot/moodle-mod_quiz-util-slot-debug.js
mod/quiz/yui/build/moodle-mod_quiz-util-slot/moodle-mod_quiz-util-slot-min.js
mod/quiz/yui/build/moodle-mod_quiz-util-slot/moodle-mod_quiz-util-slot.js
mod/quiz/yui/src/dragdrop/js/resource.js
mod/quiz/yui/src/dragdrop/meta/dragdrop.json
mod/quiz/yui/src/quizbase/js/quizbase.js
mod/quiz/yui/src/toolboxes/js/resource.js
mod/quiz/yui/src/toolboxes/js/toolbox.js
mod/quiz/yui/src/util/js/page.js
mod/quiz/yui/src/util/js/slot.js
mod/scorm/index.php
mod/scorm/loadSCO.php
mod/scorm/player.php
mod/scorm/report.php
mod/survey/index.php
mod/url/lib.php
question/engine/datalib.php
question/engine/questionattempt.php
question/engine/questionattemptstep.php
question/engine/tests/datalib_reporting_queries_test.php [moved from question/engine/tests/question_engine_data_mapper_test.php with 92% similarity]
question/engine/tests/datalib_test.php [new file with mode: 0644]
question/preview.php
question/tests/behat/edit_questions.feature
question/tests/behat/preview_question.feature
question/type/questiontypebase.php
question/type/random/questiontype.php
report/outline/index.php
report/outline/locallib.php
report/participation/index.php
report/stats/graph.php
report/stats/locallib.php
repository/recent/tests/behat/add_recent.feature
repository/tests/behat/cancel_add_file.feature
repository/tests/behat/create_shortcut.feature
repository/tests/behat/delete_files.feature
repository/tests/behat/overwrite_file.feature
tag/tag.js
tag/tag_autocomplete.php
theme/base/style/calendar.css
theme/base/style/core.css
theme/base/style/course.css
theme/base/style/grade.css
theme/bootstrapbase/layout/popup.php
theme/bootstrapbase/less/moodle/calendar.less
theme/bootstrapbase/less/moodle/core.less
theme/bootstrapbase/less/moodle/course.less
theme/bootstrapbase/less/moodle/grade.less
theme/bootstrapbase/style/moodle.css
user/editadvanced.php
user/index.php
user/lib.php
user/profile.php
version.php
webservice/rest/locallib.php
webservice/upload.php

index fd31903..b904da2 100644 (file)
@@ -23,6 +23,17 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) { // sp
     $temp->add(new admin_setting_configcheckbox('allowuserblockhiding', new lang_string('allowuserblockhiding', 'admin'), new lang_string('configallowuserblockhiding', 'admin'), 1));
     $temp->add(new admin_setting_configcheckbox('allowblockstodock', new lang_string('allowblockstodock', 'admin'), new lang_string('configallowblockstodock', 'admin'), 1));
     $temp->add(new admin_setting_configtextarea('custommenuitems', new lang_string('custommenuitems', 'admin'), new lang_string('configcustommenuitems', 'admin'), '', PARAM_TEXT, '50', '10'));
+    $temp->add(new admin_setting_configtextarea(
+        'customusermenuitems',
+        new lang_string('customusermenuitems', 'admin'),
+        new lang_string('configcustomusermenuitems', 'admin'),
+        'messages,message|/message/index.php|message
+myfiles,moodle|/user/files.php|download
+mybadges,badges|/badges/mybadges.php|award',
+        PARAM_TEXT,
+        '50',
+        '10'
+    ));
     $temp->add(new admin_setting_configcheckbox('enabledevicedetection', new lang_string('enabledevicedetection', 'admin'), new lang_string('configenabledevicedetection', 'admin'), 1));
     $temp->add(new admin_setting_devicedetectregex('devicedetectregex', new lang_string('devicedetectregex', 'admin'), new lang_string('devicedetectregex_desc', 'admin'), ''));
     $ADMIN->add('themes', $temp);
index 84a5296..15a429e 100644 (file)
@@ -112,8 +112,6 @@ if (has_capability('moodle/grade:manage', $systemcontext)
         $defaults = array('value'=>0, 'forced'=>false, 'adv'=>true);
         $temp->add(new admin_setting_gradecat_combo('grade_aggregateoutcomes', new lang_string('aggregateoutcomes', 'grades'),
                     new lang_string('aggregateoutcomes_help', 'grades'), $defaults, $options));
-        $temp->add(new admin_setting_gradecat_combo('grade_aggregatesubcats', new lang_string('aggregatesubcats', 'grades'),
-                    new lang_string('aggregatesubcats_help', 'grades'), $defaults, $options));
 
         $options = array(0 => new lang_string('none'));
         for ($i=1; $i<=20; $i++) {
index f162e05..b0135b9 100644 (file)
@@ -66,6 +66,7 @@ $string['validationmsg_filenotexists'] = 'Extracted file not found';
 $string['validationmsg_filesnumber'] = 'Not enough files found in the package';
 $string['validationmsg_filestatus'] = 'Unable to extract all files';
 $string['validationmsg_filestatus_info'] = 'Attempting to extract file {$a->file} resulted in error \'{$a->status}\'.';
+$string['validationmsg_foundlangfile'] = 'Found language file';
 $string['validationmsg_maturity'] = 'Declared maturity level';
 $string['validationmsg_maturity_help'] = 'The plugin can declare its maturity level. If the maintainer considers the plugin stable, the declared maturity level will read MATURITY_STABLE. All other maturity levels (such as alpha or beta) should be considered unstable and a warning is raised.';
 $string['validationmsg_missingexpectedlangenfile'] = 'English language file name mismatch';
index c8bd149..5967929 100644 (file)
@@ -36,6 +36,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    tool_langimport
+ * @since      Moodle 2.8
  * @copyright  2014 Dan Poltawski <dan@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 82e5270..e528da4 100644 (file)
@@ -36,6 +36,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    tool_langimport
+ * @since      Moodle 2.8
  * @copyright  2014 Dan Poltawski <dan@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 4f0528f..b9d026a 100644 (file)
@@ -36,6 +36,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    tool_langimport
+ * @since      Moodle 2.8
  * @copyright  2014 Dan Poltawski <dan@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index bcb6af5..a3c36ac 100644 (file)
@@ -67,7 +67,7 @@ class tool_messageinbound_edit_handler_form extends moodleform {
             DAYSECS => get_string('oneday', 'tool_messageinbound'),
             WEEKSECS => get_string('oneweek', 'tool_messageinbound'),
             YEARSECS => get_string('oneyear', 'tool_messageinbound'),
-            '' => get_string('noexpiry', 'tool_messageinbound'),
+            0 => get_string('noexpiry', 'tool_messageinbound'),
         );
         $mform->addElement('select', 'defaultexpiration', get_string('defaultexpiration', 'tool_messageinbound'), $options);
         $mform->addHelpButton('defaultexpiration', 'defaultexpiration', 'tool_messageinbound');
diff --git a/admin/tool/monitor/classes/event/rule_created.php b/admin/tool/monitor/classes/event/rule_created.php
new file mode 100644 (file)
index 0000000..178445b
--- /dev/null
@@ -0,0 +1,77 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * The tool_monitor rule created event.
+ *
+ * @package    tool_monitor
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_monitor\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The tool_monitor rule created event class.
+ *
+ * @package    tool_monitor
+ * @since      Moodle 2.8
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class rule_created extends \core\event\base {
+
+    /**
+     * Init method.
+     *
+     * @return void
+     */
+    protected function init() {
+        $this->data['objecttable'] = 'tool_monitor_rules';
+        $this->data['crud'] = 'c';
+        $this->data['edulevel'] = self::LEVEL_OTHER;
+    }
+
+    /**
+     * Return localised event name.
+     *
+     * @return string
+     */
+    public static function get_name() {
+        return get_string('eventrulecreated', 'tool_monitor');
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return "The user with id '$this->userid' created the event monitor rule with id '$this->objectid'.";
+    }
+
+    /**
+     * Get URL related to the action
+     *
+     * @return \moodle_url
+     */
+    public function get_url() {
+        return new \moodle_url('/admin/tool/monitor/edit.php', array('ruleid' => $this->objectid,
+            'courseid' => $this->courseid));
+    }
+}
diff --git a/admin/tool/monitor/classes/event/rule_deleted.php b/admin/tool/monitor/classes/event/rule_deleted.php
new file mode 100644 (file)
index 0000000..50e2d5b
--- /dev/null
@@ -0,0 +1,76 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * The tool_monitor rule deleted event.
+ *
+ * @package    tool_monitor
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_monitor\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The tool_monitor rule deleted event class.
+ *
+ * @package    tool_monitor
+ * @since      Moodle 2.8
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class rule_deleted extends \core\event\base {
+
+    /**
+     * Init method.
+     *
+     * @return void
+     */
+    protected function init() {
+        $this->data['objecttable'] = 'tool_monitor_rules';
+        $this->data['crud'] = 'd';
+        $this->data['edulevel'] = self::LEVEL_OTHER;
+    }
+
+    /**
+     * Return localised event name.
+     *
+     * @return string
+     */
+    public static function get_name() {
+        return get_string('eventruledeleted', 'tool_monitor');
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return "The user with id '$this->userid' deleted the event monitor rule with id '$this->objectid'.";
+    }
+
+    /**
+     * Get URL related to the action
+     *
+     * @return \moodle_url
+     */
+    public function get_url() {
+        return new \moodle_url('/admin/tool/monitor/managerules.php', array('courseid' => $this->courseid));
+    }
+}
diff --git a/admin/tool/monitor/classes/event/rule_updated.php b/admin/tool/monitor/classes/event/rule_updated.php
new file mode 100644 (file)
index 0000000..8b262c4
--- /dev/null
@@ -0,0 +1,77 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * The tool_monitor rule updated event.
+ *
+ * @package    tool_monitor
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_monitor\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The tool_monitor rule updated event class.
+ *
+ * @package    tool_monitor
+ * @since      Moodle 2.8
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class rule_updated extends \core\event\base {
+
+    /**
+     * Init method.
+     *
+     * @return void
+     */
+    protected function init() {
+        $this->data['objecttable'] = 'tool_monitor_rules';
+        $this->data['crud'] = 'u';
+        $this->data['edulevel'] = self::LEVEL_OTHER;
+    }
+
+    /**
+     * Return localised event name.
+     *
+     * @return string
+     */
+    public static function get_name() {
+        return get_string('eventruleupdated', 'tool_monitor');
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return "The user with id '$this->userid' updated the event monitor rule with id '$this->objectid'.";
+    }
+
+    /**
+     * Get URL related to the action
+     *
+     * @return \moodle_url
+     */
+    public function get_url() {
+        return new \moodle_url('/admin/tool/monitor/edit.php', array('ruleid' => $this->objectid,
+            'courseid' => $this->courseid));
+    }
+}
diff --git a/admin/tool/monitor/classes/event/subscription_created.php b/admin/tool/monitor/classes/event/subscription_created.php
new file mode 100644 (file)
index 0000000..e3d2b81
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * The tool_monitor subscription created event.
+ *
+ * @package    tool_monitor
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_monitor\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The tool_monitor subscription created event class.
+ *
+ * @package    tool_monitor
+ * @since      Moodle 2.8
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class subscription_created extends \core\event\base {
+
+    /**
+     * Init method.
+     *
+     * @return void
+     */
+    protected function init() {
+        $this->data['objecttable'] = 'tool_monitor_subscriptions';
+        $this->data['crud'] = 'c';
+        $this->data['edulevel'] = self::LEVEL_TEACHING;
+    }
+
+    /**
+     * Return localised event name.
+     *
+     * @return string
+     */
+    public static function get_name() {
+        return get_string('eventsubcreated', 'tool_monitor');
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return "The user with id '$this->userid' created the event monitor subscription with id '$this->objectid'.";
+    }
+}
diff --git a/admin/tool/monitor/classes/event/subscription_criteria_met.php b/admin/tool/monitor/classes/event/subscription_criteria_met.php
new file mode 100644 (file)
index 0000000..693bcf4
--- /dev/null
@@ -0,0 +1,86 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * The tool_monitor subscription criteria met event.
+ *
+ * @package    tool_monitor
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_monitor\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The tool_monitor subscription criteria met event class.
+ *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      - string subscriptionid: id of the subscription.
+ * }
+ *
+ * @package    tool_monitor
+ * @since      Moodle 2.8
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class subscription_criteria_met extends \core\event\base {
+
+    /**
+     * Init method.
+     *
+     * @return void
+     */
+    protected function init() {
+        $this->data['crud'] = 'c';
+        $this->data['edulevel'] = self::LEVEL_TEACHING;
+    }
+
+    /**
+     * Return localised event name.
+     *
+     * @return string
+     */
+    public static function get_name() {
+        return get_string('eventsubcriteriamet', 'tool_monitor');
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return "The criteria for the subscription with id '{$this->other['subscriptionid']}' was met.";
+    }
+
+    /**
+     * Custom validation.
+     *
+     * @throws \coding_exception
+     * @return void
+     */
+    protected function validate_data() {
+        parent::validate_data();
+
+        if (!isset($this->other['subscriptionid'])) {
+            throw new \coding_exception('The \'subscriptionid\' value must be set in other.');
+        }
+    }
+}
diff --git a/admin/tool/monitor/classes/event/subscription_deleted.php b/admin/tool/monitor/classes/event/subscription_deleted.php
new file mode 100644 (file)
index 0000000..e4b2bc0
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * The tool_monitor subscription deleted event.
+ *
+ * @package    tool_monitor
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_monitor\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The tool_monitor subscription deleted event class.
+ *
+ * @package    tool_monitor
+ * @since      Moodle 2.8
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class subscription_deleted extends \core\event\base {
+
+    /**
+     * Init method.
+     *
+     * @return void
+     */
+    protected function init() {
+        $this->data['objecttable'] = 'tool_monitor_subscriptions';
+        $this->data['crud'] = 'd';
+        $this->data['edulevel'] = self::LEVEL_TEACHING;
+    }
+
+    /**
+     * Return localised event name.
+     *
+     * @return string
+     */
+    public static function get_name() {
+        return get_string('eventsubdeleted', 'tool_monitor');
+    }
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return "The user with id '$this->userid' deleted the event monitor subscription with id '$this->objectid'.";
+    }
+}
index 27d3d29..3918a7d 100644 (file)
@@ -54,8 +54,12 @@ class eventobservers {
      */
     public static function course_deleted(\core\event\course_deleted $event) {
         $rules = rule_manager::get_rules_by_courseid($event->courseid);
+        $context = null;
+        if ($event->contextlevel == CONTEXT_COURSE) {
+            $context = $event->get_context();
+        }
         foreach ($rules as $rule) {
-            rule_manager::delete_rule($rule->id);
+            rule_manager::delete_rule($rule->id, $context);
         }
     }
 
@@ -125,6 +129,7 @@ class eventobservers {
         $select = "SELECT COUNT(id) FROM {tool_monitor_events} ";
         $now = time();
         $messagestosend = array();
+        $allsubids = array();
 
         // Let us now process the events and check for subscriptions.
         foreach ($events as $eventobj) {
@@ -132,6 +137,7 @@ class eventobservers {
             $idstosend = array();
             foreach ($subscriptions as $subscription) {
                 $starttime = $now - $subscription->timewindow;
+                $starttime = ($starttime > $subscription->lastnotificationsent) ? $starttime : $subscription->lastnotificationsent;
                 if ($subscription->courseid == 0) {
                     // Site level subscription. Count all events.
                     $where = "eventname = :eventname AND timecreated >  :starttime";
@@ -156,13 +162,46 @@ class eventobservers {
                 $count = $DB->count_records_sql($sql, $params);
                 if (!empty($count) && $count >= $subscription->frequency) {
                     $idstosend[] = $subscription->id;
+
+                    // Trigger a subscription_criteria_met event.
+                    // It's possible that the course has been deleted since the criteria was met, so in that case use
+                    // the system context. Set it here and change later if needed.
+                    $context = \context_system::instance();
+                    // We can't perform if (!empty($subscription->courseid)) below as it uses the magic method
+                    // __get to return the variable, which will always result in being empty.
+                    $courseid = $subscription->courseid;
+                    if (!empty($courseid)) {
+                        if ($coursecontext = \context_course::instance($courseid, IGNORE_MISSING)) {
+                            $context = $coursecontext;
+                        }
+                    }
+
+                    $params = array(
+                        'userid' => $subscription->userid,
+                        'courseid' => $subscription->courseid,
+                        'context' => $context,
+                        'other' => array(
+                            'subscriptionid' => $subscription->id
+                        )
+                    );
+                    $event = \tool_monitor\event\subscription_criteria_met::create($params);
+                    $event->trigger();
                 }
             }
             if (!empty($idstosend)) {
                 $messagestosend[] = array('subscriptionids' => $idstosend, 'event' => $eventobj);
+                $allsubids = array_merge($allsubids, $idstosend);
             }
         }
 
+        if (!empty($allsubids)) {
+            // Update the last trigger flag.
+            list($sql, $params) = $DB->get_in_or_equal($allsubids, SQL_PARAMS_NAMED);
+            $params['now'] = $now;
+            $sql = "UPDATE {tool_monitor_subscriptions} SET lastnotificationsent = :now WHERE id $sql";
+            $DB->execute($sql, $params);
+        }
+
         // Schedule a task to send notification.
         if (!empty($messagestosend)) {
             $adhocktask = new notification_task();
index ffb1f4a..150129c 100644 (file)
@@ -45,7 +45,9 @@ class notification_task extends \core\task\adhoc_task {
             $subscriptionids = $data->subscriptionids;
             foreach ($subscriptionids as $id) {
                 if ($message = $this->generate_message($id, $eventobj)) {
+                    mtrace("Sending message to the user with id " . $message->userto->id . " for the subscription with id $id...");
                     message_send($message);
+                    mtrace("Sent.");
                 }
             }
         }
@@ -68,6 +70,10 @@ class notification_task extends \core\task\adhoc_task {
             return false;
         }
         $user = \core_user::get_user($subscription->userid);
+        if (empty($user)) {
+            // User doesn't exist. Should never happen, nothing to do return.
+            return false;
+        }
         $context = \context_user::instance($user->id, IGNORE_MISSING);
         if ($context === false) {
             // User context doesn't exist. Should never happen, nothing to do return.
diff --git a/admin/tool/monitor/classes/output/helpicon/renderable.php b/admin/tool/monitor/classes/output/helpicon/renderable.php
deleted file mode 100644 (file)
index 3cb0395..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * The file for the renderable class for the tool_monitor help icon.
- *
- * @package    tool_monitor
- * @copyright  2014 Mark Nelson <markn@moodle.com>
- * @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 <markn@moodle.com>
- * @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
deleted file mode 100644 (file)
index 99025f2..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * The file for the renderer class for the tool_monitor help icon.
- *
- * @package    tool_monitor
- * @copyright  2014 Mark Nelson <markn@moodle.com>
- * @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 <markn@moodle.com>
- * @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'));
-    }
-}
index 2c74245..198a606 100644 (file)
@@ -64,13 +64,15 @@ class renderable extends \table_sql implements \renderable {
     public function __construct($uniqueid, \moodle_url $url, $courseid = 0, $perpage = 100) {
         parent::__construct($uniqueid);
 
+        $this->set_attribute('id', 'toolmonitorrules_table');
         $this->set_attribute('class', 'toolmonitor managerules generaltable generalbox');
-        $this->define_columns(array('name', 'description', 'plugin', 'eventname', 'filters', 'manage'));
+        $this->define_columns(array('name', 'description', 'course', 'plugin', 'eventname', 'filters', 'manage'));
         $this->define_headers(array(
-                get_string('name'),
+                get_string('rulename', 'tool_monitor'),
                 get_string('description'),
-                get_string('plugin'),
-                get_string('eventname'),
+                get_string('course'),
+                get_string('area', 'tool_monitor'),
+                get_string('event', 'tool_monitor'),
                 get_string('frequency', 'tool_monitor'),
                 get_string('manage', 'tool_monitor'),
             )
@@ -91,7 +93,6 @@ class renderable extends \table_sql implements \renderable {
      * 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) {
@@ -102,7 +103,6 @@ class renderable extends \table_sql implements \renderable {
      * 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) {
@@ -110,10 +110,26 @@ class renderable extends \table_sql implements \renderable {
     }
 
     /**
-     * Generate content for plugin column.
+     * Generate content for course column.
      *
      * @param \tool_monitor\rule $rule rule object
+     * @return string html used to display the context column field.
+     */
+    public function col_course(\tool_monitor\rule $rule) {
+        $coursename = $rule->get_course_name($this->context);
+
+        $courseid = $rule->courseid;
+        if (empty($courseid)) {
+            return $coursename;
+        } else {
+            return \html_writer::link(new \moodle_url('/course/view.php', array('id' => $this->courseid)), $coursename);
+        }
+    }
+
+    /**
+     * 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) {
@@ -124,7 +140,6 @@ class renderable extends \table_sql implements \renderable {
      * 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) {
@@ -135,7 +150,6 @@ class renderable extends \table_sql implements \renderable {
      * 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) {
@@ -146,7 +160,6 @@ class renderable extends \table_sql implements \renderable {
      * 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) {
@@ -154,7 +167,7 @@ class renderable extends \table_sql implements \renderable {
         $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)) {
+        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, 'sesskey' => sesskey()));
@@ -169,13 +182,10 @@ class renderable extends \table_sql implements \renderable {
             $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', get_string('deleterule', 'tool_monitor')), $action);
-            $manage .= $icon;
+            $icon = $OUTPUT->render(new \pix_icon('t/delete', get_string('deleterule', 'tool_monitor')));
+            $manage .= \html_writer::link($deleteurl, $icon, array('class' => 'action-icon'));
         } else {
-            $manage = '-';
+            $manage = get_string('nopermission', 'tool_monitor');
         }
         return $manage;
     }
index 889817d..5eaed9f 100644 (file)
@@ -68,7 +68,7 @@ class renderer extends \plugin_renderer_base {
     }
 
     /**
-     * Html to add a button for adding a new rul.
+     * Html to add a button for adding a new rule.
      *
      * @param int $courseid course id.
      *
@@ -81,4 +81,19 @@ class renderer extends \plugin_renderer_base {
         $addurl = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/edit.php', array('courseid' => $courseid));
         return \html_writer::link($addurl, $button);
     }
+
+    /**
+     * Html to add a link to go to the subscription page.
+     *
+     * @param moodle_url $manageurl The url of the subscription page.
+     *
+     * @return string html for the link to the subscription page.
+     */
+    public function render_subscriptions_link($manageurl) {
+        echo \html_writer::start_div();
+        $a = \html_writer::link($manageurl, get_string('managesubscriptions', 'tool_monitor'));
+        $link = \html_writer::tag('span', get_string('managesubscriptionslink', 'tool_monitor', $a));
+        echo $link;
+        echo \html_writer::end_div();
+    }
 }
index fe3f8e0..30d6b66 100644 (file)
@@ -71,8 +71,9 @@ class renderer extends \plugin_renderer_base {
      * @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);;
+        if ($select = $renderable->get_user_courses_select()) {
+            return $this->render($select);
+        }
     }
 
     /**
@@ -91,4 +92,19 @@ class renderer extends \plugin_renderer_base {
 
         return $o;
     }
+
+    /**
+     * Html to add a link to go to the rule manager page.
+     *
+     * @param moodle_url $ruleurl The url of the rule manager page.
+     *
+     * @return string html for the link to the rule manager page.
+     */
+    public function render_rules_link($ruleurl) {
+        echo \html_writer::start_div();
+        $a = \html_writer::link($ruleurl, get_string('managerules', 'tool_monitor'));
+        $link = \html_writer::tag('span', get_string('manageruleslink', 'tool_monitor', $a));
+        echo $link;
+        echo \html_writer::end_div();
+    }
 }
index f891e90..7014a35 100644 (file)
@@ -53,11 +53,6 @@ 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.
      *
@@ -67,16 +62,18 @@ 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');
-        $this->define_columns(array('name', 'description', 'select'));
+        $this->define_columns(array('name', 'description', 'course', 'plugin', 'eventname', 'filters', 'select'));
         $this->define_headers(array(
-                get_string('name'),
+                get_string('rulename', 'tool_monitor'),
                 get_string('description'),
-                get_string('select')
+                get_string('course'),
+                get_string('area', 'tool_monitor'),
+                get_string('event', 'tool_monitor'),
+                get_string('frequency', 'tool_monitor'),
+                ''
             )
         );
         $this->courseid = $courseid;
@@ -88,7 +85,6 @@ 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');
         $total = \tool_monitor\rule_manager::count_rules_by_courseid($this->courseid);
         $this->totalcount = $total;
     }
@@ -97,39 +93,92 @@ class rules extends \table_sql implements \renderable {
      * Generate content for name column.
      *
      * @param \tool_monitor\rule $rule rule object
-     *
-     * @return string html used to display the column field.
+     * @return string html used to display the rule name.
      */
     public function col_name(\tool_monitor\rule $rule) {
-        $name = $rule->get_name($this->context);
-        $helpicon = new \tool_monitor\output\helpicon\renderable('rule', $rule->id);
-        $helpicon = $this->helpiconrenderer->render($helpicon);
-
-        return $name . $helpicon;
+        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.
+     * @return string html used to display the description.
      */
     public function col_description(\tool_monitor\rule $rule) {
         return $rule->get_description($this->context);
     }
 
+    /**
+     * Generate content for course column.
+     *
+     * @param \tool_monitor\rule $rule rule object
+     * @return string html used to display the course name.
+     */
+    public function col_course(\tool_monitor\rule $rule) {
+        $coursename = $rule->get_course_name($this->context);
+
+        $courseid = $rule->courseid;
+        if (empty($courseid)) {
+            return $coursename;
+        } else {
+            return \html_writer::link(new \moodle_url('/course/view.php', array('id' => $this->courseid)), $coursename);
+        }
+    }
+
     /**
      * Generate content for plugin column.
      *
      * @param \tool_monitor\rule $rule rule object
+     * @return string html used to display the plugin name.
+     */
+    public function col_plugin(\tool_monitor\rule $rule) {
+        return $rule->get_plugin_name();
+    }
+
+    /**
+     * Generate content for eventname column.
      *
-     * @return string html used to display the column field.
+     * @param \tool_monitor\rule $rule rule object
+     * @return string html used to display the event name.
+     */
+    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.
+     */
+    public function col_filters(\tool_monitor\rule $rule) {
+        return $rule->get_filters_description();
+    }
+
+    /**
+     * Generate content for select column.
+     *
+     * @param \tool_monitor\rule $rule rule object
+     * @return string html used to display the select 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;
+
+        $options = $rule->get_subscribe_options($this->courseid);
+        $text = get_string('subscribeto', 'tool_monitor', $rule->get_name($this->context));
+
+        if ($options instanceof \single_select) {
+            $options->set_label($text, array('class' => 'accesshide'));
+            return $OUTPUT->render($options);
+        } else if ($options instanceof \moodle_url) {
+            // A \moodle_url to subscribe.
+            $icon = $OUTPUT->pix_icon('t/add', $text);
+            $link = new \action_link($options, $icon);
+            return $OUTPUT->render($link);
+        } else {
+            return $options;
+        }
     }
 
     /**
@@ -154,14 +203,24 @@ class rules extends \table_sql implements \renderable {
     /**
      * Gets a list of courses where the current user can subscribe to rules as a dropdown.
      *
-     * @return \single_select list of courses.
+     * @return \single_select|bool returns the list of courses, or false if the select box
+     *      should not be displayed.
      */
     public function get_user_courses_select() {
-        $courses = get_user_capability_course('tool/monitor:subscribe', null, true, 'fullname');
+        global $DB;
+
+        // If the number of courses on the site exceed the maximum drop down limit do not display the select box.
+        $numcourses = $DB->count_records('course');
+        if ($numcourses > COURSE_MAX_COURSES_PER_DROPDOWN) {
+            return false;
+        }
+
         $options = array(0 => get_string('site'));
-        $systemcontext = \context_system::instance();
-        foreach ($courses as $course) {
-            $options[$course->id] = format_text($course->fullname, array('context' => $systemcontext));
+        if ($courses = get_user_capability_course('tool/monitor:subscribe', null, true, 'fullname')) {
+            foreach ($courses as $course) {
+                $options[$course->id] = format_string($course->fullname, true,
+                    array('context' => \context_course::instance($course->id)));
+            }
         }
         $url = new \moodle_url('/admin/tool/monitor/index.php');
         $select = new \single_select($url, 'courseid', $options, $this->courseid);
index 8ba616d..b0403d8 100644 (file)
@@ -48,11 +48,6 @@ 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.
      *
@@ -62,18 +57,18 @@ 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');
-        $this->define_columns(array('name', 'course', 'instance', 'unsubscribe', 'editrule'));
+        $this->define_columns(array('name', 'description', 'course', 'plugin', 'eventname', 'filters', 'unsubscribe'));
         $this->define_headers(array(
-                get_string('name'),
+                get_string('rulename', 'tool_monitor'),
+                get_string('description'),
                 get_string('course'),
-                get_string('moduleinstance', 'tool_monitor'),
-                get_string('unsubscribe', 'tool_monitor'),
-                get_string('editrule', 'tool_monitor')
+                get_string('area', 'tool_monitor'),
+                get_string('event', 'tool_monitor'),
+                get_string('frequency', 'tool_monitor'),
+                get_string('unsubscribe', 'tool_monitor')
             )
         );
         $this->courseid = $courseid;
@@ -85,81 +80,89 @@ 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');
     }
 
     /**
      * Generate content for name column.
      *
      * @param \tool_monitor\subscription $sub subscription object
-     *
-     * @return string html used to display the column field.
+     * @return string html used to display the rule name.
      */
     public function col_name(\tool_monitor\subscription $sub) {
-        $name = $sub->get_name($this->context);
-        $helpicon = new \tool_monitor\output\helpicon\renderable('subscription', $sub->id);
-        $helpicon = $this->helpiconrenderer->render($helpicon);
+        return $sub->get_name($this->context);
+    }
 
-        return $name . $helpicon;
+    /**
+     * Generate content for description column.
+     *
+     * @param \tool_monitor\subscription $sub subscription object
+     * @return string html used to display the description.
+     */
+    public function col_description(\tool_monitor\subscription $sub) {
+        return $sub->get_description($this->context);
     }
 
     /**
      * Generate content for course column.
      *
      * @param \tool_monitor\subscription $sub subscription object
-     *
-     * @return string html used to display the column field.
+     * @return string html used to display the course name.
      */
     public function col_course(\tool_monitor\subscription $sub) {
-       return $sub->get_course_name($this->context);
+        $coursename = $sub->get_course_name($this->context);
+
+        $courseid = $sub->courseid;
+        if (empty($courseid)) {
+            return $coursename;
+        } else {
+            return \html_writer::link(new \moodle_url('/course/view.php', array('id' => $this->courseid)), $coursename);
+        }
     }
 
     /**
-     * Generate content for description column.
+     * Generate content for plugin column.
      *
      * @param \tool_monitor\subscription $sub subscription object
+     * @return string html used to display the plugin name.
+     */
+    public function col_plugin(\tool_monitor\subscription $sub) {
+        return $sub->get_plugin_name();
+    }
+
+    /**
+     * Generate content for eventname column.
      *
-     * @return string html used to display the column field.
+     * @param \tool_monitor\subscription $sub subscription object
+     * @return string html used to display the event name.
      */
-    public function col_instance(\tool_monitor\subscription $sub) {
-        return $sub->get_instance_name();
+    public function col_eventname(\tool_monitor\subscription $sub) {
+        return $sub->get_event_name();
     }
 
     /**
-     * Generate content for manage column.
+     * Generate content for filters column.
      *
      * @param \tool_monitor\subscription $sub subscription object
+     * @return string html used to display the filters.
+     */
+    public function col_filters(\tool_monitor\subscription $sub) {
+        return $sub->get_filters_description();
+    }
+
+    /**
+     * Generate content for unsubscribe column.
      *
-     * @return string html used to display the column field.
+     * @param \tool_monitor\subscription $sub subscription object
+     * @return string html used to display the unsubscribe 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, '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,
-                new \pix_icon('t/delete', get_string('deletesubscription', 'tool_monitor')), $action);
-        return $icon;
-    }
+        $icon = $OUTPUT->render(new \pix_icon('t/delete', get_string('deletesubscription', 'tool_monitor')));
 
-    /**
-     * 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 '-';
+        return \html_writer::link($deleteurl, $icon, array('class' => 'action-icon'));
     }
 
     /**
index 81b3aef..2a23eb1 100644 (file)
@@ -86,26 +86,40 @@ class rule {
     }
 
     /**
-     * Generate a select drop down with list of possible modules for a given course and rule.
+     * Gets the rule subscribe options for a given course and rule.
+     *
+     * Could be a select drop down with a list of possible module
+     * instances or a single link to subscribe if the rule plugin
+     * is not a module.
      *
      * @param int $courseid course id
      *
-     * @return \single_select a single select object
+     * @return \single_select|\moodle_url|string
      * @throws \coding_exception
      */
-    public function get_module_select($courseid) {
+    public function get_subscribe_options($courseid) {
         global $CFG;
-        $options = array();
-        if (strpos($this->plugin, 'mod_') === 0) {
-            $options[0] = get_string('allmodules', 'tool_monitor');
+
+        $url = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/index.php', array(
+            'courseid' => $courseid,
+            'ruleid' => $this->id,
+            'action' => 'subscribe',
+            'sesskey' => sesskey()
+        ));
+
+        if (strpos($this->plugin, 'mod_') !== 0) {
+            return $url;
+
         } else {
-            $options[0] = get_string('allevents', 'tool_monitor');
-        }
-        if (strpos($this->plugin, 'mod_') === 0) {
+            // Single select when the plugin is an activity.
+            $options = array();
+            $options[0] = get_string('allmodules', 'tool_monitor');
+
             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));
@@ -115,10 +129,9 @@ class rule {
                     $options[$cminfo->id] = $cminfo->get_formatted_name();
                 }
             }
+
+            return new \single_select($url, 'cmid', $options);
         }
-        $url = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/index.php', array('courseid' => $courseid, 'ruleid' => $this->id,
-                'action' => 'subscribe', 'sesskey' => sesskey()));
-        return new \single_select($url, 'cmid', $options, '', $nothing = array('' => 'choosedots'));
     }
 
     /**
@@ -208,10 +221,25 @@ class rule {
     }
 
     /**
-     * Get properly formatted name of the rule associated.
+     * Get properly formatted name of the course associated.
      *
      * @param \context $context context where this name would be displayed.
+     * @return string The course fullname.
+     */
+    public function get_course_name($context) {
+        $courseid = $this->courseid;
+        if (empty($courseid)) {
+            return get_string('site');
+        } else {
+            $course = get_course($courseid);
+            return format_string($course->fullname, true, array('context' => $context));
+        }
+    }
+
+    /**
+     * 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) {
@@ -222,7 +250,6 @@ class rule {
      * 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) {
index a069779..ec7beb4 100644 (file)
@@ -46,6 +46,7 @@ class rule_form extends \moodleform {
         $pluginlist = $this->_customdata['pluginlist'];
         $rule = $this->_customdata['rule'];
         $courseid = $this->_customdata['courseid'];
+        $subscriptioncount = $this->_customdata['subscriptioncount'];
 
         // General section header.
         $mform->addElement('header', 'general', get_string('general'));
@@ -85,47 +86,49 @@ class rule_form extends \moodleform {
         );
 
         // Name field.
-        $mform->addElement('text', 'name', get_string('name', 'tool_monitor'), 'size="50"');
+        $mform->addElement('text', 'name', get_string('rulename', 'tool_monitor'), 'size="50"');
         $mform->addRule('name', get_string('required'), 'required');
         $mform->setType('name', PARAM_TEXT);
-        $mform->addHelpButton('name', 'name', 'tool_monitor');
 
         // Plugin field.
-        $mform->addElement('select', 'plugin', get_string('selectplugin', 'tool_monitor'), $pluginlist);
+        $mform->addElement('select', 'plugin', get_string('areatomonitor', 'tool_monitor'), $pluginlist);
         $mform->addRule('plugin', get_string('required'), 'required');
-        $mform->addHelpButton('plugin', 'selectplugin', 'tool_monitor');
 
         // Event field.
-        $mform->addElement('select', 'eventname', get_string('selectevent', 'tool_monitor'), $eventlist);
+        $mform->addElement('select', 'eventname', get_string('event', 'tool_monitor'), $eventlist);
         $mform->addRule('eventname', get_string('required'), 'required');
-        $mform->addHelpButton('eventname', 'selectevent', 'tool_monitor');
+
+        // Freeze plugin and event fields for editing if there's a subscription for this rule.
+        if ($subscriptioncount > 0) {
+            $mform->freeze('plugin');
+            $mform->setConstant('plugin', $rule->plugin);
+            $mform->freeze('eventname');
+            $mform->setConstant('eventname', $rule->eventname);
+        }
 
         // Description field.
-        $mform->addElement('editor', 'description', get_string('description', 'tool_monitor'), $editoroptions);
-        $mform->addHelpButton('description', 'description', 'tool_monitor');
+        $mform->addElement('editor', 'description', get_string('description'), $editoroptions);
 
         // Filters.
-        $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);
+        $mform->addElement('select', 'frequency', get_string('frequency', 'tool_monitor'), $freq);
         $mform->addRule('frequency', get_string('required'), 'required');
-        $mform->addHelpButton('frequency', 'selectfrequency', 'tool_monitor');
+        $mform->addHelpButton('frequency', 'frequency', '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->addElement('select', 'minutes', get_string('inminutes', 'tool_monitor'), $mins);
         $mform->addRule('minutes', get_string('required'), 'required');
 
         // Message template.
-        $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->setDefault('template', get_string('defaultmessagetemplate', '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'));
+        $this->add_action_buttons(true, get_string('savechanges'));
     }
 
     /**
index 864451c..b0c60e0 100644 (file)
@@ -49,6 +49,26 @@ class rule_manager {
         $ruledata->timemodified = $now;
 
         $ruledata->id = $DB->insert_record('tool_monitor_rules', $ruledata);
+
+        // Trigger a rule created event.
+        if ($ruledata->id) {
+            if (!empty($ruledata->courseid)) {
+                $courseid = $ruledata->courseid;
+                $context = \context_course::instance($ruledata->courseid);
+            } else {
+                $courseid = 0;
+                $context = \context_system::instance();
+            }
+
+            $params = array(
+                'objectid' => $ruledata->id,
+                'courseid' => $courseid,
+                'context' => $context
+            );
+            $event = \tool_monitor\event\rule_created::create($params);
+            $event->trigger();
+        }
+
         return new rule($ruledata);
     }
 
@@ -85,14 +105,47 @@ class rule_manager {
      * Delete a rule and associated subscriptions, by rule id.
      *
      * @param int $ruleid id of rule to be deleted.
+     * @param \context|null $coursecontext the context of the course - this is passed when we
+     *      can not get the context via \context_course as the course has been deleted.
      *
      * @return bool
      */
-    public static function delete_rule($ruleid) {
+    public static function delete_rule($ruleid, $coursecontext = null) {
         global $DB;
 
-        subscription_manager::remove_all_subscriptions_for_rule($ruleid);
-        return $DB->delete_records('tool_monitor_rules', array('id' => $ruleid));
+        subscription_manager::remove_all_subscriptions_for_rule($ruleid, $coursecontext);
+
+        // Retrieve the rule from the DB before we delete it, so we have a record when we trigger a rule deleted event.
+        $rule = $DB->get_record('tool_monitor_rules', array('id' => $ruleid));
+
+        $success = $DB->delete_records('tool_monitor_rules', array('id' => $ruleid));
+
+        // If successful trigger a rule deleted event.
+        if ($success) {
+            // It is possible that we are deleting rules associated with a deleted course, so we should be
+            // passing the context as the second parameter.
+            if (!is_null($coursecontext)) {
+                $context = $coursecontext;
+                $courseid = $rule->courseid;
+            } else if (!empty($rule->courseid) && ($context = \context_course::instance($rule->courseid,
+                    IGNORE_MISSING))) {
+                $courseid = $rule->courseid;
+            } else {
+                $courseid = 0;
+                $context = \context_system::instance();
+            }
+
+            $params = array(
+                'objectid' => $rule->id,
+                'courseid' => $courseid,
+                'context' => $context
+            );
+            $event = \tool_monitor\event\rule_deleted::create($params);
+            $event->add_record_snapshot('tool_monitor_rules', $rule);
+            $event->trigger();
+        }
+
+        return $success;
     }
 
     /**
@@ -127,7 +180,34 @@ class rule_manager {
             throw new \coding_exception('Invalid rule ID.');
         }
         $ruledata->timemodified = time();
-        return $DB->update_record('tool_monitor_rules', $ruledata);
+
+        $success = $DB->update_record('tool_monitor_rules', $ruledata);
+
+        // If successful trigger a rule updated event.
+        if ($success) {
+            // If we do not have the course id we need to retrieve it.
+            if (!isset($ruledata->courseid)) {
+                $courseid = $DB->get_field('tool_monitor_rules', 'courseid', array('id' => $ruledata->id), MUST_EXIST);
+            } else {
+                $courseid = $ruledata->courseid;
+            }
+
+            if (!empty($courseid)) {
+                $context = \context_course::instance($courseid);
+            } else {
+                $context = \context_system::instance();
+            }
+
+            $params = array(
+                'objectid' => $ruledata->id,
+                'courseid' => $courseid,
+                'context' => $context
+            );
+            $event = \tool_monitor\event\rule_updated::create($params);
+            $event->trigger();
+        }
+
+        return $success;
     }
 
     /**
index a729dc8..6e25f6e 100644 (file)
@@ -124,7 +124,6 @@ class subscription {
      * 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) {
@@ -135,7 +134,6 @@ class subscription {
      * 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) {
@@ -162,21 +160,16 @@ class subscription {
      * 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));
+            return get_string('site');
         } 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);
+            $course = get_course($courseid);
+            return format_string($course->fullname, true, array('context' => $context));
         }
-        return $coursename;
     }
 
     /**
index 82796a3..1ecf565 100644 (file)
@@ -59,7 +59,28 @@ class subscription_manager {
         }
 
         $subscription->timecreated = time();
-        return $DB->insert_record('tool_monitor_subscriptions', $subscription);
+        $subscription->id = $DB->insert_record('tool_monitor_subscriptions', $subscription);
+
+        // Trigger a subscription created event.
+        if ($subscription->id) {
+            if (!empty($subscription->courseid)) {
+                $courseid = $subscription->courseid;
+                $context = \context_course::instance($subscription->courseid);
+            } else {
+                $courseid = 0;
+                $context = \context_system::instance();
+            }
+
+            $params = array(
+                'objectid' => $subscription->id,
+                'courseid' => $courseid,
+                'context' => $context
+            );
+            $event = \tool_monitor\event\subscription_created::create($params);
+            $event->trigger();
+        }
+
+        return $subscription->id;
     }
 
     /**
@@ -81,7 +102,33 @@ class subscription_manager {
         if ($checkuser && $subscription->userid != $USER->id) {
             throw new \coding_exception('Invalid subscription supplied');
         }
-        return $DB->delete_records('tool_monitor_subscriptions', array('id' => $subscription->id));
+
+        // Store the subscription before we delete it.
+        $subscription = $DB->get_record('tool_monitor_subscriptions', array('id' => $subscription->id));
+
+        $success = $DB->delete_records('tool_monitor_subscriptions', array('id' => $subscription->id));
+
+        // If successful trigger a subscription_deleted event.
+        if ($success) {
+            if (!empty($subscription->courseid)) {
+                $courseid = $subscription->courseid;
+                $context = \context_course::instance($subscription->courseid);
+            } else {
+                $courseid = 0;
+                $context = \context_system::instance();
+            }
+
+            $params = array(
+                'objectid' => $subscription->id,
+                'courseid' => $courseid,
+                'context' => $context
+            );
+            $event = \tool_monitor\event\subscription_deleted::create($params);
+            $event->add_record_snapshot('tool_monitor_subscriptions', $subscription);
+            $event->trigger();
+        }
+
+        return $success;
     }
 
     /**
@@ -112,12 +159,51 @@ class subscription_manager {
      * Delete all subscribers for a given rule.
      *
      * @param int $ruleid rule id.
+     * @param \context|null $coursecontext the context of the course - this is passed when we
+     *      can not get the context via \context_course as the course has been deleted.
      *
      * @return bool
      */
-    public static function remove_all_subscriptions_for_rule($ruleid) {
+    public static function remove_all_subscriptions_for_rule($ruleid, $coursecontext = null) {
         global $DB;
-        return $DB->delete_records('tool_monitor_subscriptions', array('ruleid' => $ruleid));
+
+        // Store all the subscriptions we have to delete.
+        $subscriptions = $DB->get_recordset('tool_monitor_subscriptions', array('ruleid' => $ruleid));
+
+        // Now delete them.
+        $success = $DB->delete_records('tool_monitor_subscriptions', array('ruleid' => $ruleid));
+
+        // If successful and there were subscriptions that were deleted trigger a subscription deleted event.
+        if ($success && $subscriptions) {
+            foreach ($subscriptions as $subscription) {
+                // It is possible that we are deleting rules associated with a deleted course, so we should be
+                // passing the context as the second parameter.
+                if (!is_null($coursecontext)) {
+                    $context = $coursecontext;
+                    $courseid = $subscription->courseid;
+                } else if (!empty($subscription->courseid) && ($coursecontext =
+                        \context_course::instance($subscription->courseid, IGNORE_MISSING))) {
+                    $courseid = $subscription->courseid;
+                    $context = $coursecontext;
+                } else {
+                    $courseid = 0;
+                    $context = \context_system::instance();
+                }
+
+                $params = array(
+                    'objectid' => $subscription->id,
+                    'courseid' => $courseid,
+                    'context' => $context
+                );
+                $event = \tool_monitor\event\subscription_deleted::create($params);
+                $event->add_record_snapshot('tool_monitor_subscriptions', $subscription);
+                $event->trigger();
+            }
+        }
+
+        $subscriptions->close();
+
+        return $success;
     }
 
     /**
@@ -279,4 +365,19 @@ class subscription_manager {
         }
         return $result;
     }
+
+    /**
+     * Get count of subscriptions for a given rule.
+     *
+     * @param int $ruleid rule id of the subscription.
+     *
+     * @return int number of subscriptions
+     */
+    public static function count_rule_subscriptions($ruleid) {
+        global $DB;
+        $sql = self::get_subscription_join_rule_sql(true);
+        $sql .= "WHERE s.ruleid = :ruleid";
+
+        return $DB->count_records_sql($sql, array('ruleid' => $ruleid));
+    }
 }
diff --git a/admin/tool/monitor/classes/task/clean_events.php b/admin/tool/monitor/classes/task/clean_events.php
new file mode 100644 (file)
index 0000000..9efb360
--- /dev/null
@@ -0,0 +1,142 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Clean the tool_monitor_events table.
+ *
+ * @package    tool_monitor
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_monitor\task;
+
+/**
+ * Simple task to clean the tool_monitor_events table.
+ */
+class clean_events extends \core\task\scheduled_task {
+
+    /**
+     * Get a descriptive name for this task.
+     *
+     * @return string
+     */
+    public function get_name() {
+        return get_string('taskcleanevents', 'tool_monitor');
+    }
+
+    /**
+     * Performs the cleaning of events.
+     */
+    public function execute() {
+        global $DB;
+
+        // Array to store which events have been triggered in which course.
+        $courses = array();
+
+        // Firstly, let's go through the site wide rules. There may be multiple rules for the site that rely on
+        // the same event being triggered, so we only remove the events when they reach the max timewindow.
+        if ($siterules = $DB->get_recordset('tool_monitor_rules', array('courseid' => 0), 'timewindow DESC')) {
+            // Go through each rule and check if there are any events we can remove.
+            foreach ($siterules as $rule) {
+                // Check if we have already processed this event.
+                if (isset($courses[$rule->courseid][$rule->eventname])) {
+                    continue;
+                }
+                // Store the timewindow for this event.
+                $courses[$rule->courseid][$rule->eventname] = $rule->timewindow;
+                // Delete any events that may exist that have exceeded the timewindow.
+                $DB->delete_records_select('tool_monitor_events', 'eventname = :eventname AND
+                    courseid = :courseid AND timecreated <= :timewindow',
+                    array('eventname' => $rule->eventname, 'courseid' => $rule->courseid,
+                        'timewindow' => time() - $rule->timewindow));
+            }
+            // Free resources.
+            $siterules->close();
+        }
+
+        // Now, get the course rules. The same applies here - there may be multiple rules for the course that rely on
+        // the same event being triggered, so we only remove the events when they reach the max timewindow.
+        if ($rules = $DB->get_recordset_select('tool_monitor_rules', 'courseid != 0', array(), 'timewindow DESC')) {
+            // Go through each rule and check if there are any events we can remove.
+            foreach ($rules as $rule) {
+                // Check if we have already processed this event for this particular course.
+                if (isset($courses[$rule->courseid][$rule->eventname])) {
+                    continue;
+                }
+                // Add the course and event to the list.
+                $courses[$rule->courseid][$rule->eventname] = $rule->timewindow;
+                // If there is a site wide rule listening for this event do not remove it unless the maximum
+                // timewindow between the two has exceeded.
+                $timewindow = $rule->timewindow;
+                if (isset($courses[0][$rule->eventname]) && ($courses[0][$rule->eventname] > $timewindow)) {
+                    $timewindow = $courses[0][$rule->eventname];
+                }
+                // Delete any events that may exist that have exceeded the timewindow.
+                $DB->delete_records_select('tool_monitor_events', 'eventname = :eventname AND
+                    courseid = :courseid AND timecreated <= :timewindow',
+                        array('eventname' => $rule->eventname, 'courseid' => $rule->courseid,
+                            'timewindow' => time() - $timewindow));
+            }
+            // Free resources.
+            $rules->close();
+        }
+
+        if ($siterules || $rules) { // Check that there are rules present.
+            // Get a list of all the events we have been through.
+            $allevents = array();
+            foreach ($courses as $key => $value) {
+                foreach ($courses[$key] as $event => $notused) {
+                    $allevents[] = $event;
+                }
+            }
+            // Remove all the events in the table that are not applicable to any rule. There may be a rule in one course
+            // listening for a certain event, but not in another course, so we can delete the event from the course
+            // where there is no rule. We also have to consider site wide rules. We may have an event that is triggered
+            // in a course we can't remove because there is a site wide rule for this event.
+            if ($events = $DB->get_recordset('tool_monitor_events')) {
+                // Array to store which events we need to remove.
+                $eventstodelete = array();
+                // Store the current time.
+                $now = time();
+                foreach ($events as $event) {
+                    // If the event is not required for a course rule and there is no site wide rule for it, or
+                    // it has extended past or equal to the timewindow for the site rule - it can be deleted.
+                    if (!isset($courses[$event->courseid][$event->eventname]) && (!isset($courses[0][$event->eventname])
+                        || $courses[0][$event->eventname] <= ($now - $event->timecreated))) {
+                        $eventstodelete[] = $event->id;
+                    }
+                }
+                // Free resources.
+                $events->close();
+
+                // Remove the events.
+                if (!empty($eventstodelete)) {
+                    list($eventidsql, $params) = $DB->get_in_or_equal($eventstodelete);
+                    $DB->delete_records_select('tool_monitor_events', "id $eventidsql", $params);
+                }
+            }
+
+            // Remove all the events in the table that are not used by any rule.
+            if (!empty($allevents)) {
+                list($eventnamesql, $params) = $DB->get_in_or_equal($allevents, SQL_PARAMS_QM, 'param', false);
+                $DB->delete_records_select('tool_monitor_events', "eventname $eventnamesql", $params);
+            }
+        } else { // No rules, just remove everything.
+            $DB->delete_records('tool_monitor_events');
+        }
+    }
+}
index 39d2bb9..7729199 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<XMLDB PATH="tool/monitor/db" VERSION="20140708" COMMENT="XMLDB file for Moodle tool/monitor"
+<XMLDB PATH="tool/monitor/db" VERSION="20141103" COMMENT="XMLDB file for Moodle tool/monitor"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
 >
@@ -37,6 +37,7 @@
         <FIELD NAME="cmid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Course module id"/>
         <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="User id of the subscriber"/>
         <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Timestamp of when this subscription was created"/>
+        <FIELD NAME="lastnotificationsent" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Timestamp of the time when a notification was last sent for this subscription."/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
diff --git a/admin/tool/monitor/db/tasks.php b/admin/tool/monitor/db/tasks.php
new file mode 100644 (file)
index 0000000..e70c344
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file defines tasks performed by the tool.
+ *
+ * @package    tool_monitor
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+// List of tasks.
+$tasks = array(
+    array(
+        'classname' => 'tool_monitor\task\clean_events',
+        'blocking' => 0,
+        'minute' => '*',
+        'hour' => '*',
+        'day' => '*',
+        'dayofweek' => '*',
+        'month' => '*'
+    )
+);
diff --git a/admin/tool/monitor/db/upgrade.php b/admin/tool/monitor/db/upgrade.php
new file mode 100644 (file)
index 0000000..59f0e86
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Upgrade scirpt for tool_monitor.
+ *
+ * @package    tool_monitor
+ * @copyright  2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Upgrade the plugin.
+ *
+ * @param int $oldversion
+ * @return bool always true
+ */
+function xmldb_tool_monitor_upgrade($oldversion) {
+    global $DB;
+
+    $dbman = $DB->get_manager();
+
+    if ($oldversion < 2014102000) {
+
+        // Define field lastnotificationsent to be added to tool_monitor_subscriptions.
+        $table = new xmldb_table('tool_monitor_subscriptions');
+        $field = new xmldb_field('lastnotificationsent', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'timecreated');
+
+        // Conditionally launch add field lastnotificationsent.
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+
+        // Monitor savepoint reached.
+        upgrade_plugin_savepoint(true, 2014102000, 'tool', 'monitor');
+    }
+
+    return true;
+}
index c69e92e..20bd3c4 100644 (file)
@@ -44,17 +44,12 @@ if (empty($courseid)) {
 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);
 $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->set_title($coursename);
+$PAGE->set_heading($coursename);
 
 // Get data ready for mform.
 $eventlist = tool_monitor\eventlist::get_all_eventlist(true);
@@ -78,12 +73,19 @@ if (empty($courseid)) {
 if (!empty($ruleid)) {
     $rule = \tool_monitor\rule_manager::get_rule($ruleid)->get_mform_set_data();
     $rule->minutes = $rule->timewindow / MINSECS;
+    $subscriptioncount = \tool_monitor\subscription_manager::count_rule_subscriptions($ruleid);
 } else {
     $rule = new stdClass();
+    $subscriptioncount = 0;
 }
 
 $mform = new tool_monitor\rule_form(null, array('eventlist' => $eventlist, 'pluginlist' => $pluginlist, 'rule' => $rule,
-        'courseid' => $courseid));
+        'courseid' => $courseid, 'subscriptioncount' => $subscriptioncount));
+
+if ($mform->is_cancelled()) {
+    redirect(new moodle_url('/admin/tool/monitor/managerules.php', array('courseid' => $courseid)));
+    exit();
+}
 
 if ($mformdata = $mform->get_data()) {
     $rule = \tool_monitor\rule_manager::clean_ruledata_form($mformdata);
@@ -98,7 +100,21 @@ if ($mformdata = $mform->get_data()) {
 } else {
     echo $OUTPUT->header();
     $mform->set_data($rule);
+    // If there's any subscription for this rule, display an information message.
+    if ($subscriptioncount > 0) {
+        echo $OUTPUT->notification(get_string('disablefieldswarning', 'tool_monitor'), 'notifyproblem');
+    }
     $mform->display();
     echo $OUTPUT->footer();
+    exit;
 }
 
+echo $OUTPUT->header();
+if (!empty($ruleid)) {
+    echo $OUTPUT->heading(get_string('editrule', 'tool_monitor'));
+} else {
+    echo $OUTPUT->heading(get_string('addrule', 'tool_monitor'));
+}
+$mform->set_data($rule);
+$mform->display();
+echo $OUTPUT->footer();
diff --git a/admin/tool/monitor/help.php b/admin/tool/monitor/help.php
deleted file mode 100644 (file)
index 572b4ba..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Displays help on a new page.
- *
- * @copyright 2014 Mark Nelson <markn@moodle.com>
- * @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
deleted file mode 100644 (file)
index 429ff3b..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Displays help via AJAX call.
- *
- * @copyright 2014 Mark Nelson <markn@moodle.com>
- * @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));
index 45c7309..e6fd7d1 100644 (file)
@@ -30,6 +30,7 @@ $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);
+$confirm = optional_param('confirm', false, PARAM_BOOL);
 
 // Validate course id.
 if (empty($courseid)) {
@@ -50,18 +51,11 @@ $sitename = format_string($SITE->fullname, true, array('context' => $context));
 $PAGE->set_context($context);
 
 // Set up the page.
-$a = new stdClass();
-$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));
-
+$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);
-
-echo $OUTPUT->header();
+$PAGE->set_title($sitename);
+$PAGE->set_heading($sitename);
 
 // Create/delete subscription if needed.
 if (!empty($action)) {
@@ -70,14 +64,38 @@ if (!empty($action)) {
         case 'subscribe' :
             $rule = \tool_monitor\rule_manager::get_rule($ruleid);
             $rule->subscribe_user($courseid, $cmid);
+            echo $OUTPUT->header();
             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');
+            // If the subscription does not exist, then redirect back as the subscription must have already been deleted.
+            if (!$subscription = $DB->record_exists('tool_monitor_subscriptions', array('id' => $subscriptionid))) {
+                redirect(new moodle_url('/admin/tool/monitor/index.php', array('courseid' => $courseid)));
+            }
+
+            // Set the URLs.
+            $confirmurl = new moodle_url('/admin/tool/monitor/index.php', array('subscriptionid' => $subscriptionid,
+                'courseid' => $courseid, 'action' => 'unsubscribe', 'confirm' => true,
+                'sesskey' => sesskey()));
+            $cancelurl = new moodle_url('/admin/tool/monitor/index.php', array('subscriptionid' => $subscriptionid,
+                'courseid' => $courseid, 'sesskey' => sesskey()));
+            if ($confirm) {
+                \tool_monitor\subscription_manager::delete_subscription($subscriptionid);
+                echo $OUTPUT->header();
+                echo $OUTPUT->notification(get_string('subdeletesuccess', 'tool_monitor'), 'notifysuccess');
+            } else {
+                $subscription = \tool_monitor\subscription_manager::get_subscription($subscriptionid);
+                echo $OUTPUT->header();
+                echo $OUTPUT->confirm(get_string('subareyousure', 'tool_monitor', $subscription->get_name($context)),
+                    $confirmurl, $cancelurl);
+                echo $OUTPUT->footer();
+                exit();
+            }
             break;
         default:
     }
+} else {
+    echo $OUTPUT->header();
 }
 
 // Render the current subscriptions list.
@@ -86,20 +104,27 @@ $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 $OUTPUT->heading(get_string('currentsubscriptions', 'tool_monitor'), 3);
     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'));
+echo $OUTPUT->heading(get_string('rulescansubscribe', 'tool_monitor'), 3);
 $rules = new \tool_monitor\output\managesubs\rules('toolmonitorrules', $indexurl, $courseid);
 echo $renderer->render($rules);
+
+// Check if the user can manage the course rules we are viewing.
+if (empty($courseid)) {
+    $canmanagerules = has_capability('tool/monitor:managerules', $context);
+} else {
+    $canmanagerules = has_capability('tool/monitor:managerules', $coursecontext);
+}
 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)) {
+    if ($canmanagerules) {
         $manageurl = new moodle_url("/admin/tool/monitor/managerules.php", array('courseid' => $courseid));
         $a = html_writer::link($manageurl, get_string('managerules', 'tool_monitor'));
         $link = "&nbsp;";
@@ -107,5 +132,8 @@ if (empty($totalrules)) {
         echo $link;
     }
     echo html_writer::end_div();
+} else if ($canmanagerules) {
+    $manageurl = new moodle_url("/admin/tool/monitor/managerules.php", array('courseid' => $courseid));
+    echo $renderer->render_rules_link($manageurl);
 }
 echo $OUTPUT->footer();
index bfac799..2a57c94 100644 (file)
 
 $string['addrule'] = 'Add a new rule';
 $string['allevents'] = 'All events';
-$string['allmodules'] = 'All modules';
+$string['allmodules'] = 'All instances';
+$string['area'] = 'Area';
+$string['areatomonitor'] = 'Area to monitor';
 $string['core'] = 'Core';
-$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}';
+$string['defaultmessagetemplate'] = 'The rule "{rulename}" you have subscribed to has occurred - please find further details at {link}';
 $string['deleterule'] = 'Delete rule';
 $string['deletesubscription'] = 'Delete subscription';
 $string['description'] = 'Description:';
+$string['disablefieldswarning'] = 'Plugin and events fields can not be edited because this rule already has subscriptions.';
 $string['duplicaterule'] = 'Duplicate rule';
 $string['editrule'] = 'Edit rule';
+$string['event'] = 'Event';
 $string['eventnotfound'] = 'Event not found';
+$string['eventrulecreated'] = 'Rule created';
+$string['eventruledeleted'] = 'Rule deleted';
+$string['eventruleupdated'] = 'Rule updated';
+$string['eventsubcreated'] = 'Subscription created';
+$string['eventsubcriteriamet'] = 'Subscription criteria met';
+$string['eventsubdeleted'] = 'Subscription deleted';
 $string['errorincorrectevent'] = 'Please select an event related to the selected plugin';
-$string['freqdesc'] = '{$a->freq} times in {$a->mins} minutes';
-$string['frequency'] = 'Frequency';
+$string['freqdesc'] = '{$a->freq} time(s) in {$a->mins} minute(s)';
+$string['frequency'] = 'Notification threshold';
+$string['frequency_help'] = 'The number of events within a specified time period required for a notification message to be sent.';
+$string['inminutes'] = 'in minutes';
 $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['manageruleslink'] = 'You can manage rules from the {$a} page.';
+$string['managesubscriptionslink'] = 'You can subscribe to rules from the {$a} page.';
 $string['manage'] = 'Manage';
 $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';
-$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.
-<br /> {link} - Link to the location where the event happened.
-<br /> {modulelink} - Link to the module where the event has happened.
-<br /> {rulename} - Name of this rule.
-<br /> {description} - Rule description.
-<br /> {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['nopermission'] = 'No permission';
+$string['messagetemplate'] = 'Notification message';
+$string['messagetemplate_help'] = 'A notification message is sent to subscribers once the notification threshold has been reached. It can include any or all of the following placeholders:
+<br /><br />
+* Link to the location of the event {link}<br />
+* Link to the area monitored {modulelink}<br />
+* Rule name {rulename}<br />
+* Description {description}<br />
+* Event {eventname}';
+$string['monitor:managerules'] = 'Manage event monitor rules';
+$string['monitor:subscribe'] = 'Subscribe to event monitor rules';
+$string['norules'] = 'There are no event monitoring rules.';
 $string['pluginname'] = 'Event monitor';
 $string['processevents'] = 'Process events';
+$string['rulename'] = 'Rule name';
 $string['ruleareyousure'] = 'Are you sure you want to delete rule "{$a}"?';
 $string['rulecopysuccess'] = 'Rule successfully duplicated';
 $string['ruledeletesuccess'] = 'Rule successfully deleted';
@@ -72,20 +82,12 @@ $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. Please note that some events are only triggered for the entire site (e.g. 'course created') and will never trigger when subscribed to from within a course.";
-$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. 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";
 $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['monitor:managerules'] = 'Manage event monitor rules';
-$string['monitor:subscribe'] = 'Subscribe to event monitor rules';
+$string['subscribeto'] = 'Subscribe to rule "{$a}"';
+$string['taskcleanevents'] = 'Removes any unnecessary event monitor events';
 $string['unsubscribe'] = 'Unsubscribe';
 
index e49cdcc..d06ec5e 100644 (file)
@@ -56,7 +56,7 @@ function tool_monitor_extend_navigation_course($navigation, $course, $context) {
  */
 function tool_monitor_extend_navigation_user_settings($navigation, $user, $usercontext, $course, $coursecontext) {
     global $USER;
-    if (($USER->id == $user->id)) {
+    if (($USER->id == $user->id) && (has_capability('tool/monitor:subscribe', $coursecontext))) {
         $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', ''));
index 8259fec..8a664b0 100644 (file)
@@ -28,6 +28,7 @@ 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);
+$confirm = optional_param('confirm', false, PARAM_BOOL);
 
 // Validate course id.
 if (empty($courseid)) {
@@ -46,28 +47,28 @@ if (empty($courseid)) {
 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);
+$PAGE->set_title($coursename);
+$PAGE->set_heading($coursename);
 
 // Site level report.
 if (empty($courseid)) {
     admin_externalpage_setup('toolmonitorrules', '', null, '', array('pagelayout' => 'report'));
 }
 
-echo $OUTPUT->header();
-
 // Copy/delete rule if needed.
 if (!empty($action) && $ruleid) {
     require_sesskey();
-    $rule = \tool_monitor\rule_manager::get_rule($ruleid);
+
+    // If the rule does not exist, then redirect back as the rule must have already been deleted.
+    if (!$rule = $DB->get_record('tool_monitor_rules', array('id' => $ruleid), '*', IGNORE_MISSING)) {
+        redirect(new moodle_url('/admin/tool/monitor/managerules.php', array('courseid' => $courseid)));
+    }
+
+    echo $OUTPUT->header();
+    $rule = \tool_monitor\rule_manager::get_rule($rule);
     if ($rule->can_manage_rule()) {
         switch ($action) {
             case 'copy' :
@@ -75,8 +76,20 @@ if (!empty($action) && $ruleid) {
                 echo $OUTPUT->notification(get_string('rulecopysuccess', 'tool_monitor'), 'notifysuccess');
                 break;
             case 'delete' :
-                $rule->delete_rule();
-                echo $OUTPUT->notification(get_string('ruledeletesuccess', 'tool_monitor'), 'notifysuccess');
+                $confirmurl = new moodle_url($CFG->wwwroot. '/admin/tool/monitor/managerules.php',
+                    array('ruleid' => $ruleid, 'courseid' => $courseid, 'action' => 'delete',
+                        'confirm' => true, 'sesskey' => sesskey()));
+                $cancelurl = new moodle_url($CFG->wwwroot. '/admin/tool/monitor/managerules.php',
+                    array('courseid' => $courseid));
+                if ($confirm) {
+                    $rule->delete_rule();
+                    echo $OUTPUT->notification(get_string('ruledeletesuccess', 'tool_monitor'), 'notifysuccess');
+                } else {
+                    echo $OUTPUT->confirm(get_string('ruleareyousure', 'tool_monitor', $rule->get_name($context)),
+                        $confirmurl, $cancelurl);
+                    echo $OUTPUT->footer();
+                    exit();
+                }
                 break;
             default:
         }
@@ -84,10 +97,18 @@ if (!empty($action) && $ruleid) {
         // User doesn't have permissions. Should never happen for real users.
         throw new moodle_exception('rulenopermissions', 'tool_monitor', $manageurl, $action);
     }
+} else {
+    echo $OUTPUT->header();
 }
 
+echo $OUTPUT->heading(get_string('managerules', 'tool_monitor'));
+
 // 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);
+if (has_capability('tool/monitor:subscribe', $context)) {
+    $manageurl = new moodle_url("/admin/tool/monitor/index.php", array('courseid' => $courseid));
+    echo $renderer->render_subscriptions_link($manageurl);
+}
 echo $OUTPUT->footer();
index 9e32468..1913b84 100644 (file)
  */
 defined('MOODLE_INTERNAL') || die;
 
-if ($hassiteconfig) {
-
-    // 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('reports', $temp);
-}
+// Manage rules page.
+$temp = new admin_externalpage(
+    'toolmonitorrules',
+    get_string('managerules', 'tool_monitor'),
+    new moodle_url('/admin/tool/monitor/managerules.php', array('courseid' => 0)),
+    'tool/monitor:managerules'
+);
+$ADMIN->add('reports', $temp);
index 80f74d3..1458133 100644 (file)
@@ -14,148 +14,148 @@ Feature: tool_monitor_rule
     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 "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                             |
-      | 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 "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                               |
-      | 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
+    And I log in as "admin"
+    And I follow "Course 1"
+    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                             |
+      | plugin               | Forum                                             |
+      | eventname            | Post created                                      |
+      | id_description       | I want a rule to monitor posts created on a forum |
+      | frequency            | 1                                                 |
+      | minutes              | 1                                                 |
+      | Notification message | The forum post was created. {modulelink}          |
+    And I press "Save changes"
+    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                               |
+      | plugin               | Forum                                             |
+      | eventname            | Post created                                      |
+      | id_description       | I want a rule to monitor posts created on a forum |
+      | frequency            | 1                                                 |
+      | minutes              | 1                                                 |
+      | Notification message | 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 "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                                          |
-      | 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"
+    And I am on homepage
+    And I follow "Course 1"
+    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                                          |
+      | plugin               | Forum                                             |
+      | eventname            | Post created                                      |
+      | id_description       | I want a rule to monitor posts created on a forum |
+      | frequency            | 1                                                 |
+      | minutes              | 1                                                 |
+      | Notification message | The forum post was created. {modulelink}          |
+    And I press "Save changes"
+    Then "New rule" row "Course" column of "toolmonitorrules_table" table should contain "Course 1"
+    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 time(s) in 1 minute(s)"
 
   Scenario: Delete a rule on course level
     Given I log in as "teacher1"
-    And   I follow "Course 1"
-    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"
-    And   I should see "Rule successfully deleted"
-    And   I should not see "New rule course level"
+    And I follow "Course 1"
+    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 "Continue"
+    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 "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                                  |
-      | 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"
+    And I follow "Course 1"
+    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                                  |
+      | plugin               | Quiz                                           |
+      | eventname            | Quiz attempt deleted                           |
+      | id_description       | I want a rule to monitor quiz attempts deleted |
+      | frequency            | 5                                              |
+      | minutes              | 5                                              |
+      | Notification message | 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 time(s) in 5 minute(s)"
 
   Scenario: Duplicate a rule on course level
     Given I log in as "teacher1"
-    And   I follow "Course 1"
-    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"
-    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"
+    And I follow "Course 1"
+    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"
+    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 time(s) in 1 minute(s)"
 
   Scenario: Add a rule on site level
     Given I log in as "admin"
-    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                                          |
-      | 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"
+    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                                          |
+      | plugin               | Forum                                             |
+      | eventname            | Post created                                      |
+      | id_description       | I want a rule to monitor posts created on a forum |
+      | frequency            | 1                                                 |
+      | minutes              | 1                                                 |
+      | Notification message | The forum post was created. {modulelink}          |
+    And I press "Save changes"
+    Then "New rule" row "Course" column of "toolmonitorrules_table" table should contain "Site"
+    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 time(s) in 1 minute(s)"
 
   Scenario: Delete a rule on site level
     Given I log in as "admin"
-    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"
-    And   I should see "Rule successfully deleted"
-    And   I should not see "New rule site level"
+    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 "Continue"
+    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 "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                                  |
-      | 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"
+    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                                  |
+      | plugin               | Quiz                                           |
+      | eventname            | Quiz attempt deleted                           |
+      | id_description       | I want a rule to monitor quiz attempts deleted |
+      | frequency            | 5                                              |
+      | minutes              | 5                                              |
+      | Notification message | 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 time(s) in 5 minute(s)"
 
   Scenario: Duplicate a rule on site level
     Given I log in as "admin"
-    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"
-    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"
+    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"
+    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 time(s) in 1 minute(s)"
index 8d78a0a..ccc8762 100644 (file)
@@ -14,112 +14,123 @@ Feature: tool_monitor_subscriptions
     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 "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                             |
-      | 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 "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                               |
-      | 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
+    And I log in as "admin"
+    And I follow "Course 1"
+    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                             |
+      | plugin               | Core                                              |
+      | eventname            | Course viewed                                     |
+      | id_description       | I want a rule to monitor when a course is viewed. |
+      | frequency            | 1                                                 |
+      | minutes              | 1                                                 |
+      | Notification message | The course was viewed. {modulelink}               |
+    And I press "Save changes"
+    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                               |
+      | plugin               | Core                                              |
+      | eventname            | Course viewed                                     |
+      | id_description       | I want a rule to monitor when a course is viewed. |
+      | frequency            | 1                                                 |
+      | minutes              | 1                                                 |
+      | Notification message | 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 "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
+    And I follow "Course 1"
+    And I navigate to "Event monitoring" node in "My profile settings"
+    And I set the field "Select a course" to "Course 1"
+    When I follow "Subscribe to rule \"New rule course level\""
+    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 "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"
-    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
+    And I follow "Course 1"
+    And I navigate to "Event monitoring" node in "My profile settings"
+    And I set the field "Select a course" to "Course 1"
+    And I follow "Subscribe to rule \"New rule course level\""
+    And I should see "Subscription successfully created"
+    When I click on "Delete subscription" "link" in the "New rule course level" "table_row"
+    And I should see "Are you sure you want to delete this subscription for the rule \"New rule course level\"?"
+    And I press "Continue"
+    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 "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
+    And I navigate to "Event monitoring" node in "My profile settings"
+    And I set the field "Select a course" to "Site"
+    When I follow "Subscribe to rule \"New rule site level\""
+    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 "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
-    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
+    And I navigate to "Event monitoring" node in "My profile settings"
+    And I set the field "Select a course" to "Site"
+    And I follow "Subscribe to rule \"New rule site level\""
+    And I should see "Subscription successfully created"
+    And "#toolmonitorsubs_r0" "css_element" should exist
+    When I click on "Delete subscription" "link" in the "New rule site level" "table_row"
+    And I should see "Are you sure you want to delete this subscription for the rule \"New rule site level\"?"
+    And I press "Continue"
+    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 "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
-    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."
+    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 "Event monitoring" node in "My profile settings"
+    And I set the field "Select a course" to "Site"
+    And I follow "Subscribe to rule \"New rule site level\""
+    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
+    When I navigate to "Messages" node in "My profile"
+    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 "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
-    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."
+    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 "Event monitoring" node in "My profile settings"
+    And I set the field "Select a course" to "Course 1"
+    And I follow "Subscribe to rule \"New rule course level\""
+    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
+    When I navigate to "Messages" node in "My profile"
+    And I follow "Do not reply to this email (1)"
+    Then I should see "The course was viewed."
+
+  Scenario: Navigating via quick link to rules
+    Given I log in as "admin"
+    When I navigate to "Event monitoring" node in "My profile settings"
+    Then I should see "You can manage rules from the Event monitoring rules page."
+    And I follow "Event monitoring rules"
+    And I should see "Event monitor"
+    And I should see "You can subscribe to rules from the Event monitoring page."
+    And I log out
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I navigate to "Event monitoring" node in "My profile settings"
+    And I should see "You can manage rules from the Event monitoring rules page."
index b8d178a..f9d0ed0 100644 (file)
@@ -46,16 +46,17 @@ class tool_monitor_eventobservers_testcase extends advanced_testcase {
         $this->resetAfterTest(true);
 
         $user = $this->getDataGenerator()->create_user();
-        $course = $this->getDataGenerator()->create_course();
+        $course1 = $this->getDataGenerator()->create_course();
+        $course2 = $this->getDataGenerator()->create_course();
         $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor');
 
         $rule = new stdClass();
         $rule->userid = $user->id;
-        $rule->courseid = $course->id;
+        $rule->courseid = $course1->id;
         $rule->plugin = 'test';
 
         $sub = new stdClass();
-        $sub->courseid = $course->id;
+        $sub->courseid = $course1->id;
         $sub->userid = $user->id;
 
         // Add 10 rules for this course with subscriptions.
@@ -65,9 +66,9 @@ class tool_monitor_eventobservers_testcase extends advanced_testcase {
             $monitorgenerator->create_subscription($sub);
         }
 
-        // Add 10 random rules for random courses.
+        // Add 10 random rules for course 2.
+        $rule->courseid = $course2->id;
         for ($i = 0; $i < 10; $i++) {
-            $rule->courseid = rand(10000000, 50000000);
             $createdrule = $monitorgenerator->create_rule($rule);
             $sub->courseid = $rule->courseid;
             $sub->ruleid = $createdrule->id;
@@ -77,24 +78,24 @@ class tool_monitor_eventobservers_testcase extends advanced_testcase {
         // 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);
+        $courserules = \tool_monitor\rule_manager::get_rules_by_courseid($course1->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);
+        $coursesubs = \tool_monitor\subscription_manager::get_user_subscriptions_for_course($course1->id, 0, 0, $user->id);
         $this->assertCount(10, $coursesubs);
 
         // Let us delete the course now.
-        delete_course($course->id, false);
+        delete_course($course1->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);
+        $courserules = \tool_monitor\rule_manager::get_rules_by_courseid($course1->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);
+        $coursesubs = \tool_monitor\subscription_manager::get_user_subscriptions_for_course($course1->id, 0, 0, $user->id);
         $this->assertCount(0, $coursesubs); // Making sure all subscriptions are deleted.
     }
 
@@ -265,14 +266,63 @@ class tool_monitor_eventobservers_testcase extends advanced_testcase {
         $this->verify_processed_data($msgsink);
     }
 
+    /**
+     * Test that same events are not used twice to calculate conditions for a single subscription.
+     */
+    public function test_multiple_notification_not_sent() {
+        global $USER;
+
+        $this->resetAfterTest();
+        $this->setAdminUser();
+        $messagesink = $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 = 5;
+
+        $rule = $toolgenerator->create_rule($rulerecord);
+
+        $subrecord = new stdClass();
+        $subrecord->courseid = $course->id;
+        $subrecord->ruleid = $rule->id;
+        $subrecord->userid = $USER->id;
+        $toolgenerator->create_subscription($subrecord);
+
+        for ($i = 0; $i < 7; $i++) {
+            // Now let us trigger 7 instances of the event.
+            $event = \mod_book\event\course_module_instance_list_viewed::create_from_course($course);
+            $event->trigger();
+            sleep(1); // Add a second delay, to prevent time collisions.
+        }
+        $this->run_adhock_tasks();
+        $messages = $messagesink->get_messages();
+        $this->assertCount(1, $messages); // There should be only one message not 3.
+        for ($i = 0; $i < 3; $i++) {
+            // Now let us trigger 5 more instances of the event.
+            $event = \mod_book\event\course_module_instance_list_viewed::create_from_course($course);
+            $event->trigger();
+        }
+
+        $this->run_adhock_tasks();
+        $messages = $messagesink->get_messages();
+        $this->assertCount(2, $messages); // There should be two messages now.
+    }
+
     /**
      * Run adhoc tasks.
      */
     protected function run_adhock_tasks() {
+        ob_start();
         while ($task = \core\task\manager::get_next_adhoc_task(time())) {
             $task->execute();
             \core\task\manager::adhoc_task_complete($task);
         }
+        ob_clean(); // Suppress mtrace debugging info.
     }
 
     /**
@@ -374,16 +424,17 @@ class tool_monitor_eventobservers_testcase extends advanced_testcase {
         $this->resetAfterTest(true);
 
         $user = $this->getDataGenerator()->create_user();
-        $course = $this->getDataGenerator()->create_course();
+        $course1 = $this->getDataGenerator()->create_course();
+        $course2 = $this->getDataGenerator()->create_course();
         $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor');
 
         $rule = new stdClass();
         $rule->userid = $user->id;
-        $rule->courseid = $course->id;
+        $rule->courseid = $course1->id;
         $rule->plugin = 'test';
 
         $sub = new stdClass();
-        $sub->courseid = $course->id;
+        $sub->courseid = $course1->id;
         $sub->userid = $user->id;
 
         // Add 10 rules for this course with subscriptions.
@@ -393,9 +444,9 @@ class tool_monitor_eventobservers_testcase extends advanced_testcase {
             $monitorgenerator->create_subscription($sub);
         }
 
-        // Add 10 random rules for random courses.
+        // Add 10 random rules for course 2.
+        $rule->courseid = $course2->id;
         for ($i = 0; $i < 10; $i++) {
-            $rule->courseid = rand(10000000, 50000000);
             $createdrule = $monitorgenerator->create_rule($rule);
             $sub->courseid = $rule->courseid;
             $sub->ruleid = $createdrule->id;
@@ -428,21 +479,22 @@ class tool_monitor_eventobservers_testcase extends advanced_testcase {
         $this->resetAfterTest(true);
 
         $user = $this->getDataGenerator()->create_user();
-        $course = $this->getDataGenerator()->create_course();
+        $course1 = $this->getDataGenerator()->create_course();
+        $course2 = $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;
+        $cm->course = $course1->id;
         $book = $this->getDataGenerator()->create_module('book', $cm);
 
         $rule = new stdClass();
         $rule->userid = $user->id;
-        $rule->courseid = $course->id;
+        $rule->courseid = $course1->id;
         $rule->plugin = 'test';
 
         $sub = new stdClass();
-        $sub->courseid = $course->id;
+        $sub->courseid = $course1->id;
         $sub->userid = $user->id;
         $sub->cmid = $book->cmid;
 
@@ -453,9 +505,9 @@ class tool_monitor_eventobservers_testcase extends advanced_testcase {
             $monitorgenerator->create_subscription($sub);
         }
 
-        // Add 10 random rules for random courses.
+        // Add 10 random rules for course 2.
+        $rule->courseid = $course2->id;
         for ($i = 0; $i < 10; $i++) {
-            $rule->courseid = rand(10000000, 50000000);
             $createdrule = $monitorgenerator->create_rule($rule);
             $sub->courseid = $rule->courseid;
             $sub->ruleid = $createdrule->id;
diff --git a/admin/tool/monitor/tests/events_test.php b/admin/tool/monitor/tests/events_test.php
new file mode 100644 (file)
index 0000000..730e18d
--- /dev/null
@@ -0,0 +1,341 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Events tests.
+ *
+ * @package    tool_monitor
+ * @category   test
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Tests that the tool_monitor events are valid and triggered correctly.
+ */
+class tool_monitor_events_testcase extends advanced_testcase {
+
+    /**
+     * Tests set up.
+     */
+    public function setUp() {
+        $this->resetAfterTest();
+    }
+
+    /**
+     * Test the rule created event.
+     */
+    public function test_rule_created() {
+        // Create the items we need to create a rule.
+        $course = $this->getDataGenerator()->create_course();
+        $user = $this->getDataGenerator()->create_user();
+
+        // Create the variables for the rule we want to create.
+        $ruledata = new stdClass();
+        $ruledata->userid = $user->id;
+        $ruledata->courseid = $course->id;
+        $ruledata->description = 'Rule description';
+        $ruledata->descriptionformat = FORMAT_HTML;
+        $ruledata->template = 'A message template';
+        $ruledata->templateformat = FORMAT_HTML;
+        $ruledata->frequency = 1;
+        $ruledata->timewindow = 60;
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        $rule = \tool_monitor\rule_manager::add_rule($ruledata);
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Confirm that the event contains the expected values.
+        $this->assertInstanceOf('\tool_monitor\event\rule_created', $event);
+        $this->assertEquals(context_course::instance($course->id), $event->get_context());
+        $this->assertEquals($rule->id, $event->objectid);
+        $this->assertEventContextNotUsed($event);
+
+        // Now let's add a system rule (courseid = 0).
+        $ruledata->courseid = 0;
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        \tool_monitor\rule_manager::add_rule($ruledata);
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Confirm that the event uses the system context.
+        $this->assertInstanceOf('\tool_monitor\event\rule_created', $event);
+        $this->assertEquals(context_system::instance(), $event->get_context());
+    }
+
+    /**
+     * Test the rule updated event.
+     */
+    public function test_rule_updated() {
+        // Create the items we need.
+        $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor');
+        $course = $this->getDataGenerator()->create_course();
+
+        // Create the rule we are going to update.
+        $createrule = new stdClass();
+        $createrule->courseid = $course->id;
+        $rule = $monitorgenerator->create_rule($createrule);
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        $updaterule = new stdClass();
+        $updaterule->id = $rule->id;
+        \tool_monitor\rule_manager::update_rule($updaterule);
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Confirm that the event contains the expected values.
+        $this->assertInstanceOf('\tool_monitor\event\rule_updated', $event);
+        $this->assertEquals(context_course::instance($course->id), $event->get_context());
+        $this->assertEquals($rule->id, $event->objectid);
+        $this->assertEventContextNotUsed($event);
+
+        // Now let's update a system rule (courseid = 0).
+        $createrule->courseid = 0;
+        $rule = $monitorgenerator->create_rule($createrule);
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        $updaterule = new stdClass();
+        $updaterule->id = $rule->id;
+        \tool_monitor\rule_manager::update_rule($updaterule);
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Confirm that the event uses the system context.
+        $this->assertInstanceOf('\tool_monitor\event\rule_updated', $event);
+        $this->assertEquals(context_system::instance(), $event->get_context());
+    }
+
+    /**
+     * Test the rule deleted event.
+     */
+    public function test_rule_deleted() {
+        // Create the items we need.
+        $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor');
+        $course = $this->getDataGenerator()->create_course();
+
+        // Create the rule we are going to delete.
+        $createrule = new stdClass();
+        $createrule->courseid = $course->id;
+        $rule = $monitorgenerator->create_rule($createrule);
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        \tool_monitor\rule_manager::delete_rule($rule->id);
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Confirm that the event contains the expected values.
+        $this->assertInstanceOf('\tool_monitor\event\rule_deleted', $event);
+        $this->assertEquals(context_course::instance($course->id), $event->get_context());
+        $this->assertEquals($rule->id, $event->objectid);
+        $this->assertEventContextNotUsed($event);
+
+        // Now let's delete a system rule (courseid = 0).
+        $createrule = new stdClass();
+        $createrule->courseid = 0;
+        $rule = $monitorgenerator->create_rule($createrule);
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        \tool_monitor\rule_manager::delete_rule($rule->id);
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Confirm that the event uses the system context.
+        $this->assertInstanceOf('\tool_monitor\event\rule_deleted', $event);
+        $this->assertEquals(context_system::instance(), $event->get_context());
+    }
+
+    /**
+     * Test the subscription created event.
+     */
+    public function test_subscription_created() {
+        // Create the items we need to test this.
+        $user = $this->getDataGenerator()->create_user();
+        $course = $this->getDataGenerator()->create_course();
+        $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor');
+
+        // Create a rule to subscribe to.
+        $rule = $monitorgenerator->create_rule();
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        $subscriptionid = \tool_monitor\subscription_manager::create_subscription($rule->id, $course->id, 0, $user->id);
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Confirm that the event contains the expected values.
+        $this->assertInstanceOf('\tool_monitor\event\subscription_created', $event);
+        $this->assertEquals(context_course::instance($course->id), $event->get_context());
+        $this->assertEquals($subscriptionid, $event->objectid);
+        $this->assertEventContextNotUsed($event);
+
+        // Create a system subscription - trigger and capture the event.
+        $sink = $this->redirectEvents();
+        \tool_monitor\subscription_manager::create_subscription($rule->id, 0, 0, $user->id);
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Confirm that the event uses the system context.
+        $this->assertInstanceOf('\tool_monitor\event\subscription_created', $event);
+        $this->assertEquals(context_system::instance(), $event->get_context());
+    }
+
+    /**
+     * Test the subscription deleted event.
+     */
+    public function test_subscription_deleted() {
+        // Create the items we need to test this.
+        $user = $this->getDataGenerator()->create_user();
+        $course = $this->getDataGenerator()->create_course();
+        $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor');
+
+        // Create a rule to subscribe to.
+        $rule = $monitorgenerator->create_rule();
+
+        $sub = new stdClass();
+        $sub->courseid = $course->id;
+        $sub->userid = $user->id;
+        $sub->ruleid = $rule->id;
+
+        // Create the subscription we are going to delete.
+        $subscription = $monitorgenerator->create_subscription($sub);
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        \tool_monitor\subscription_manager::delete_subscription($subscription->id, false);
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Confirm that the event contains the expected values.
+        $this->assertInstanceOf('\tool_monitor\event\subscription_deleted', $event);
+        $this->assertEquals(context_course::instance($course->id), $event->get_context());
+        $this->assertEquals($subscription->id, $event->objectid);
+        $this->assertEventContextNotUsed($event);
+
+        // Now let's delete a system subscription.
+        $sub = new stdClass();
+        $sub->courseid = 0;
+        $sub->userid = $user->id;
+        $sub->ruleid = $rule->id;
+
+        // Create the subscription we are going to delete.
+        $subscription = $monitorgenerator->create_subscription($sub);
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        \tool_monitor\subscription_manager::delete_subscription($subscription->id, false);
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Confirm that the event uses the system context.
+        $this->assertInstanceOf('\tool_monitor\event\subscription_deleted', $event);
+        $this->assertEquals(context_system::instance(), $event->get_context());
+
+        // Now, create a bunch of subscriptions for the rule we created.
+        $subids = array();
+        $sub->courseid = $course->id;
+        for ($i = 1; $i <= 10; $i++) {
+            $sub->userid = $i;
+            $subscription = $monitorgenerator->create_subscription($sub);
+            $subids[$subscription->id] = $subscription;
+        }
+
+        // Trigger and capture the events.
+        $sink = $this->redirectEvents();
+        \tool_monitor\subscription_manager::remove_all_subscriptions_for_rule($rule->id);
+        $events = $sink->get_events();
+
+        // Check that there were 10 events in total.
+        $this->assertCount(10, $events);
+
+        // Get all the events and ensure they are valid.
+        foreach ($events as $event) {
+            $this->assertInstanceOf('\tool_monitor\event\subscription_deleted', $event);
+            $this->assertEquals(context_course::instance($course->id), $event->get_context());
+            $this->assertEventContextNotUsed($event);
+            $this->assertArrayHasKey($event->objectid, $subids);
+            unset($subids[$event->objectid]);
+        }
+
+        // We should have found all the subscriptions.
+        $this->assertEmpty($subids);
+    }
+
+    /**
+     * Test the subscription criteria met event.
+     */
+    public function test_subscription_criteria_met() {
+        // Create the items we need to test this.
+        $user = $this->getDataGenerator()->create_user();
+        $course = $this->getDataGenerator()->create_course();
+        $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
+        $bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
+        $chapter = $bookgenerator->create_chapter(array('bookid' => $book->id));
+        $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor');
+
+        // Create a rule we want to subscribe to.
+        $rule = new stdClass();
+        $rule->userid = $user->id;
+        $rule->courseid = $course->id;
+        $rule->plugin = 'mod_book';
+        $rule->eventname = '\mod_book\event\chapter_viewed';
+        $rule->frequency = 1;
+        $rule->timewindow = 60;
+        $rule = $monitorgenerator->create_rule($rule);
+
+        // Create the subscription.
+        $sub = new stdClass();
+        $sub->courseid = $course->id;
+        $sub->userid = $user->id;
+        $sub->ruleid = $rule->id;
+        $monitorgenerator->create_subscription($sub);
+
+        // Now create the \mod_book\event\chapter_viewed event we are listening for.
+        $context = context_module::instance($book->cmid);
+        $event = \mod_book\event\chapter_viewed::create_from_chapter($book, $context, $chapter);
+
+        // Trigger and capture the event.
+        $sink = $this->redirectEvents();
+        \tool_monitor\eventobservers::process_event($event);
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Confirm that the event contains the expected values.
+        $this->assertInstanceOf('\tool_monitor\event\subscription_criteria_met', $event);
+        $this->assertEquals(context_course::instance($course->id), $event->get_context());
+        $this->assertEventContextNotUsed($event);
+    }
+}
index f9e05dc..1296791 100644 (file)
@@ -108,11 +108,14 @@ class tool_monitor_rule_manager_testcase extends advanced_testcase {
 
         $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor');
 
+        $course1 = $this->getDataGenerator()->create_course();
+        $course2 = $this->getDataGenerator()->create_course();
+
         $record = new stdClass();
-        $record->courseid = 3;
+        $record->courseid = $course1->id;
 
         $record2 = new stdClass();
-        $record2->courseid = 4;
+        $record2->courseid = $course2->id;
 
         $ruleids = array();
         for ($i = 0; $i < 10; $i++) {
@@ -122,8 +125,8 @@ class tool_monitor_rule_manager_testcase extends advanced_testcase {
             $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));
+        $ruledata = \tool_monitor\rule_manager::get_rules_by_courseid($course1->id);
+        $this->assertEmpty(array_merge(array_diff(array_keys($ruledata), $ruleids), array_diff($ruleids, array_keys($ruledata))));
         $this->assertCount(20, $ruledata);
     }
 
@@ -150,7 +153,7 @@ class tool_monitor_rule_manager_testcase extends advanced_testcase {
         }
 
         $ruledata = \tool_monitor\rule_manager::get_rules_by_plugin('core');
-        $this->assertEquals($ruleids, array_keys($ruledata));
+        $this->assertEmpty(array_merge(array_diff(array_keys($ruledata), $ruleids), array_diff($ruleids, array_keys($ruledata))));
         $this->assertCount(10, $ruledata);
     }
 
diff --git a/admin/tool/monitor/tests/subscription_manager_test.php b/admin/tool/monitor/tests/subscription_manager_test.php
new file mode 100644 (file)
index 0000000..3a905ef
--- /dev/null
@@ -0,0 +1,78 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit tests for subscription manager api.
+ *
+ * @package    tool_monitor
+ * @category   test
+ * @copyright  2014 onwards Simey Lameze <simey@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+
+/**
+ * Tests for subscription manager.
+ *
+ * Class tool_monitor_subscription_manager_testcase.
+ */
+class tool_monitor_subscription_manager_testcase extends advanced_testcase {
+
+    /**
+     * Test count_rule_subscriptions method.
+     */
+    public function test_count_rule_subscriptions() {
+
+        $this->setAdminUser();
+        $this->resetAfterTest(true);
+
+        // Create users.
+        $user1 = $this->getDataGenerator()->create_user();
+        $user2 = $this->getDataGenerator()->create_user();
+
+        // Create few rules.
+        $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor');
+        $rule1 = $monitorgenerator->create_rule();
+        $rule2 = $monitorgenerator->create_rule();
+        $subs = \tool_monitor\subscription_manager::count_rule_subscriptions($rule1->id);
+
+        // No subscriptions at this point.
+        $this->assertEquals(0, $subs);
+
+        // Subscribe user 1 to rule 1.
+        $record = new stdClass;
+        $record->ruleid = $rule1->id;
+        $record->userid = $user1->id;
+        $monitorgenerator->create_subscription($record);
+
+        // Subscribe user 2 to rule 1.
+        $record->userid = $user2->id;
+        $monitorgenerator->create_subscription($record);
+
+        // Subscribe user 2 to rule 2.
+        $record->ruleid = $rule2->id;
+        $monitorgenerator->create_subscription($record);
+
+        // Should have 2 subscriptions for rule 1 and 1 subscription for rule 2
+        $subs1 = \tool_monitor\subscription_manager::count_rule_subscriptions($rule1->id);
+        $subs2 = \tool_monitor\subscription_manager::count_rule_subscriptions($rule2->id);
+        $this->assertEquals(2, $subs1);
+        $this->assertEquals(1, $subs2);
+    }
+}
\ No newline at end of file
diff --git a/admin/tool/monitor/tests/task_clean_events_test.php b/admin/tool/monitor/tests/task_clean_events_test.php
new file mode 100644 (file)
index 0000000..0e87e9e
--- /dev/null
@@ -0,0 +1,219 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit tests for the tool_monitor clean events task.
+ *
+ * @package    tool_monitor
+ * @category   test
+ * @copyright  2014 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+
+/**
+ * Class used to test the tool_monitor clean events task.
+ */
+class tool_monitor_task_clean_events_testcase extends advanced_testcase {
+
+    /**
+     * Test set up.
+     */
+    public function setUp() {
+        $this->resetAfterTest(true);
+    }
+
+    /**
+     * Tests the cleaning up of events.
+     */
+    public function test_clean_events() {
+        global $DB;
+
+        // Create the necessary items for testing.
+        $user = $this->getDataGenerator()->create_user();
+        $course = $this->getDataGenerator()->create_course();
+        $bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
+        $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
+        $bookcontext = context_module::instance($book->cmid);
+        $bookchapter = $bookgenerator->create_chapter(array('bookid' => $book->id));
+        $course2 = $this->getDataGenerator()->create_course();
+        $book2 = $this->getDataGenerator()->create_module('book', array('course' => $course2->id));
+        $book2context = context_module::instance($book2->cmid);
+        $book2chapter = $bookgenerator->create_chapter(array('bookid' => $book2->id));
+        $monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor');
+
+        // Let's set some data for the rules we need before we can generate them.
+        $rule = new stdClass();
+        $rule->userid = $user->id;
+        $rule->courseid = $course->id;
+        $rule->plugin = 'mod_book';
+        $rule->eventname = '\mod_book\event\course_module_viewed';
+        $rule->timewindow = 500;
+
+        // Let's add a few rules we want to monitor.
+        $rule1 = $monitorgenerator->create_rule($rule);
+
+        $rule->eventname = '\mod_book\event\course_module_instance_list_viewed';
+        $rule2 = $monitorgenerator->create_rule($rule);
+
+        // Add the same rules for the same course, but this time with a lower timewindow (used to test that we do not
+        // remove an event for a course if there is still a rule where the maximum timewindow has not been reached).
+        $rule->eventname = '\mod_book\event\course_module_viewed';
+        $rule->timewindow = 200;
+        $rule3 = $monitorgenerator->create_rule($rule);
+
+        $rule->eventname = '\mod_book\event\course_module_instance_list_viewed';
+        $rule4 = $monitorgenerator->create_rule($rule);
+
+        // Add another rule in a different course.
+        $rule->courseid = $course2->id;
+        $rule->eventname = '\mod_book\event\chapter_viewed';
+        $rule->timewindow = 200;
+        $rule5 = $monitorgenerator->create_rule($rule);
+
+        // Add a site wide rule.
+        $rule->courseid = 0;
+        $rule->eventname = '\mod_book\event\chapter_viewed';
+        $rule->timewindow = 500;
+        $rule6 = $monitorgenerator->create_rule($rule);
+
+        // Now let's populate the tool_monitor table with the events associated with those rules.
+        \mod_book\event\course_module_viewed::create_from_book($book, $bookcontext)->trigger();
+        \mod_book\event\course_module_instance_list_viewed::create_from_course($course)->trigger();
+        \mod_book\event\chapter_viewed::create_from_chapter($book, $bookcontext, $bookchapter)->trigger();
+
+        // Let's trigger the viewed events again, but in another course. The rules created for these events are
+        // associated with another course, so these events should get deleted when we trigger the cleanup task.
+        \mod_book\event\course_module_viewed::create_from_book($book2, $book2context)->trigger();
+        \mod_book\event\course_module_instance_list_viewed::create_from_course($course2)->trigger();
+        // Trigger a chapter_viewed event in this course - this should not get deleted as the rule is site wide.
+        \mod_book\event\chapter_viewed::create_from_chapter($book2, $book2context, $book2chapter)->trigger();
+
+        // Trigger a bunch of other events.
+        $eventparams = array(
+            'context' => context_course::instance($course->id)
+        );
+        for ($i = 0; $i < 5; $i++) {
+            \mod_quiz\event\course_module_instance_list_viewed::create($eventparams)->trigger();
+            \mod_scorm\event\course_module_instance_list_viewed::create($eventparams)->trigger();
+        }
+
+        // Check that the events exist - there will be additional events for creating courses, modules and rules.
+        $this->assertEquals(26, $DB->count_records('tool_monitor_events'));
+
+        // Run the task and check that all the quiz, scorm and rule events are removed as well as the course_module_*
+        // viewed events in the second course.
+        $task = new \tool_monitor\task\clean_events();
+        $task->execute();
+
+        $events = $DB->get_records('tool_monitor_events', array(), 'id');
+        $this->assertEquals(4, count($events));
+        $event1 = array_shift($events);
+        $event2 = array_shift($events);
+        $event3 = array_shift($events);
+        $event4 = array_shift($events);
+        $this->assertEquals('\mod_book\event\course_module_viewed', $event1->eventname);
+        $this->assertEquals($course->id, $event1->courseid);
+        $this->assertEquals('\mod_book\event\course_module_instance_list_viewed', $event2->eventname);
+        $this->assertEquals($course->id, $event2->courseid);
+        $this->assertEquals('\mod_book\event\chapter_viewed', $event3->eventname);
+        $this->assertEquals($course->id, $event3->courseid);
+        $this->assertEquals('\mod_book\event\chapter_viewed', $event4->eventname);
+        $this->assertEquals($course2->id, $event4->courseid);
+
+        // Update the timewindow for two of the rules.
+        $updaterule = new stdClass();
+        $updaterule->id = $rule1->id;
+        $updaterule->timewindow = 0;
+        \tool_monitor\rule_manager::update_rule($updaterule);
+        $updaterule->id = $rule2->id;
+        \tool_monitor\rule_manager::update_rule($updaterule);
+
+        // Run the task and check that the events remain as we still have not reached the maximum timewindow.
+        $task = new \tool_monitor\task\clean_events();
+        $task->execute();
+
+        $this->assertEquals(4, $DB->count_records('tool_monitor_events'));
+
+        // Now, remove the rules associated with course_module_* events so they get deleted.
+        \tool_monitor\rule_manager::delete_rule($rule1->id);
+        \tool_monitor\rule_manager::delete_rule($rule2->id);
+        \tool_monitor\rule_manager::delete_rule($rule3->id);
+        \tool_monitor\rule_manager::delete_rule($rule4->id);
+
+        // Run the task and check all the course_module_* events are gone.
+        $task = new \tool_monitor\task\clean_events();
+        $task->execute();
+
+        // We now should only have the chapter_viewed events.
+        $events = $DB->get_records('tool_monitor_events', array(), 'id');
+        $this->assertEquals(2, count($events));
+        $event1 = array_shift($events);
+        $event2 = array_shift($events);
+        $this->assertEquals('\mod_book\event\chapter_viewed', $event1->eventname);
+        $this->assertEquals($course->id, $event1->courseid);
+        $this->assertEquals('\mod_book\event\chapter_viewed', $event2->eventname);
+        $this->assertEquals($course2->id, $event2->courseid);
+
+        // Set the timewindow of the rule for the event chapter_viewed in the second course to 0.
+        $updaterule->id = $rule5->id;
+        \tool_monitor\rule_manager::update_rule($updaterule);
+
+        // Run the task.
+        $task = new \tool_monitor\task\clean_events();
+        $task->execute();
+
+        // Check that nothing was deleted as we still have a site wide rule for the chapter_viewed event.
+        $this->assertEquals(2, $DB->count_records('tool_monitor_events'));
+
+        // Set the timewindow back to 500.
+        $updaterule->id = $rule5->id;
+        $updaterule->timewindow = 500;
+        \tool_monitor\rule_manager::update_rule($updaterule);
+
+        // Set the site rule timewindow to 0.
+        $updaterule->id = $rule6->id;
+        $updaterule->timewindow = 0;
+        \tool_monitor\rule_manager::update_rule($updaterule);
+
+        // Run the task.
+        $task = new \tool_monitor\task\clean_events();
+        $task->execute();
+
+        // We now should only have one chapter_viewed event for the second course.
+        $events = $DB->get_records('tool_monitor_events');
+        $this->assertEquals(1, count($events));
+        $event1 = array_shift($events);
+        $this->assertEquals('\mod_book\event\chapter_viewed', $event1->eventname);
+        $this->assertEquals($course2->id, $event1->courseid);
+
+        // Remove the site rule.
+        \tool_monitor\rule_manager::delete_rule($rule6->id);
+
+        // Remove the last remaining rule.
+        \tool_monitor\rule_manager::delete_rule($rule5->id);
+
+        // Run the task.
+        $task = new \tool_monitor\task\clean_events();
+        $task->execute();
+
+        // There should be no events left.
+        $this->assertEquals(0, $DB->count_records('tool_monitor_events'));
+    }
+}
index dba3696..9231910 100644 (file)
@@ -26,6 +26,6 @@
 
 defined('MOODLE_INTERNAL') || die;
 
-$plugin->version   = 2014061900;       // The current plugin version (Date: YYYYMMDDXX).
+$plugin->version   = 2014102000;       // 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).
index 79184dd..a11a2be 100644 (file)
Binary files a/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-debug.js and b/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-debug.js differ
index c62a013..bf74086 100644 (file)
Binary files a/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-min.js and b/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown-min.js differ
index 79184dd..a11a2be 100644 (file)
Binary files a/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown.js and b/admin/tool/monitor/yui/build/moodle-tool_monitor-dropdown/moodle-tool_monitor-dropdown.js differ
index ff839b6..1dff1af 100644 (file)
@@ -55,6 +55,9 @@ Y.extend(DropDown, Y.Base, {
     initializer: function() {
         this.plugin = Y.one(SELECTORS.PLUGIN);
         this.eventname = Y.one(SELECTORS.EVENTNAME);
+        var selection = this.eventname.get('value'); // Get selected event name.
+        this.updateEventsList();
+        this.updateSelection(selection);
         this.plugin.on('change', this.updateEventsList, this);
     },
 
@@ -83,6 +86,20 @@ Y.extend(DropDown, Y.Base, {
             }
         }, this);
 
+    },
+
+    /**
+     * Method to update the selected node from the options list.
+     *
+     * @method updateSelection
+     * @param {string} selection The options node value that should be selected.
+     */
+    updateSelection: function(selection) {
+        this.eventname.get('options').each(function(opt) {
+            if (opt.get('value') === selection) {
+                opt.set('selected', 'selected');
+            }
+        }, this);
     }
 }, {
     NAME: 'dropDown',
index fd33545..a173e72 100644 (file)
@@ -35,6 +35,13 @@ global $CFG;
  */
 class tool_uploadcourse_course_testcase extends advanced_testcase {
 
+    /**
+     * Tidy up open files that may be left open.
+     */
+    protected function tearDown() {
+        gc_collect_cycles();
+    }
+
     public function test_proceed_without_prepare() {
         $this->resetAfterTest(true);
         $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
index 1dd20dc..2d2ec04 100644 (file)
@@ -36,6 +36,13 @@ require_once($CFG->libdir . '/csvlib.class.php');
  */
 class tool_uploadcourse_processor_testcase extends advanced_testcase {
 
+    /**
+     * Tidy up open files that may be left open.
+     */
+    protected function tearDown() {
+        gc_collect_cycles();
+    }
+
     public function test_basic() {
         global $DB;
         $this->resetAfterTest(true);
index 25775cb..accf417 100644 (file)
@@ -35,12 +35,12 @@ function get_selection_data($ufiltering) {
 
     if ($scount) {
         if ($scount < MAX_BULK_USERS) {
-            $in = implode(',', $SESSION->bulk_users);
+            $bulkusers = $SESSION->bulk_users;
         } else {
             $bulkusers = array_slice($SESSION->bulk_users, 0, MAX_BULK_USERS, true);
-            $in = implode(',', $bulkusers);
         }
-        $userlist['susers'] = $DB->get_records_select_menu('user', "id IN ($in)", null, 'fullname', 'id,'.$DB->sql_fullname().' AS fullname');
+        list($in, $inparams) = $DB->get_in_or_equal($bulkusers);
+        $userlist['susers'] = $DB->get_records_select_menu('user', "id $in", $inparams, 'fullname', 'id,'.$DB->sql_fullname().' AS fullname');
     }
 
     return $userlist;
index 64f34f3..3931ea9 100644 (file)
@@ -52,14 +52,9 @@ class auth_db_testcase extends advanced_testcase {
             set_config('host', $CFG->dbhost.':'.$CFG->dboptions['dbport'], 'auth/db');
         }
 
-        switch (get_class($DB)) {
-            case 'mssql_native_moodle_database':
-                set_config('type', 'mssql_n', 'auth/db');
-                set_config('sybasequoting', '1', 'auth/db');
-                break;
+        switch ($DB->get_dbfamily()) {
 
-            case 'mariadb_native_moodle_database':
-            case 'mysqli_native_moodle_database':
+            case 'mysql':
                 set_config('type', 'mysqli', 'auth/db');
                 set_config('setupsql', "SET NAMES 'UTF-8'", 'auth/db');
                 set_config('sybasequoting', '0', 'auth/db');
@@ -72,12 +67,12 @@ class auth_db_testcase extends advanced_testcase {
                 }
                 break;
 
-            case 'oci_native_moodle_database':
+            case 'oracle':
                 set_config('type', 'oci8po', 'auth/db');
                 set_config('sybasequoting', '1', 'auth/db');
                 break;
 
-            case 'pgsql_native_moodle_database':
+            case 'postgres':
                 set_config('type', 'postgres7', 'auth/db');
                 $setupsql = "SET NAMES 'UTF-8'";
                 if (!empty($CFG->dboptions['dbschema'])) {
@@ -98,13 +93,17 @@ class auth_db_testcase extends advanced_testcase {
                 }
                 break;
 
-            case 'sqlsrv_native_moodle_database':
-                set_config('type', 'mssqlnative', 'auth/db');
+            case 'mssql':
+                if (get_class($DB) == 'mssql_native_moodle_database') {
+                    set_config('type', 'mssql_n', 'auth/db');
+                } else {
+                    set_config('type', 'mssqlnative', 'auth/db');
+                }
                 set_config('sybasequoting', '1', 'auth/db');
                 break;
 
             default:
-                throw new exception('Unknown database driver '.get_class($DB));
+                throw new exception('Unknown database family ' . $DB->get_dbfamily());
         }
 
         $table = new xmldb_table('auth_db_users');
index 2803711..0b014bb 100644 (file)
@@ -41,13 +41,16 @@ class auth_plugin_manual extends auth_plugin_base {
      * The name of the component. Used by the configuration.
      */
     const COMPONENT_NAME = 'auth_manual';
+    const LEGACY_COMPONENT_NAME = 'auth/manual';
 
     /**
      * Constructor.
      */
     function auth_plugin_manual() {
         $this->authtype = 'manual';
-        $this->config = get_config(self::COMPONENT_NAME);
+        $config = get_config(self::COMPONENT_NAME);
+        $legacyconfig = get_config(self::LEGACY_COMPONENT_NAME);
+        $this->config = (object)array_merge((array)$legacyconfig, (array)$config);
     }
 
     /**
index 34ede3b..959c2fb 100644 (file)
@@ -96,7 +96,7 @@ class behat_auth extends behat_base {
         // hamburger.
 
         // However, the user menu *always* needs to be expanded.
-        $xpath ="//div[@class='usermenu']//a[contains(concat(' ', @class, ' '), ' toggle-display ')]";
+        $xpath = "//div[@class='usermenu']//a[contains(concat(' ', @class, ' '), ' toggle-display ')]";
         array_unshift($steps, new When('I click on "'.$xpath.'" "xpath_element"'));
 
         return $steps;
index df9e085..e2250e2 100644 (file)
@@ -342,7 +342,8 @@ class availability_profile_condition_testcase extends advanced_testcase {
         // The list of fields should include the text field added in setUp(),
         // but should not include the textarea field added just now.
         $fields = condition::get_custom_profile_fields();
-        $this->assertEquals(array('frogtype'), array_keys($fields));
+        $this->assertArrayHasKey('frogtype', $fields);
+        $this->assertArrayNotHasKey('longtext', $fields);
     }
 
     /**
index 332a956..0728dac 100644 (file)
@@ -338,7 +338,7 @@ class cc2moodle {
 
                     $replace_values = array($i,
                                             $i - 1,
-                                            $topic['title'],
+                                            entities::safexml($topic['title']),
                                             $node_node_course_sections_section_mods_mod);
 
                 } else {
index 5265fa0..bbdfd7f 100644 (file)
@@ -1292,7 +1292,9 @@ class moodle1_question_bank_handler extends moodle1_xml_handler {
      * Closes the questions wrapper
      */
     public function on_questions_end() {
-        $this->xmlwriter->end_tag('questions');
+        if ($this->questionswrapperwritten) {
+            $this->xmlwriter->end_tag('questions');
+        }
     }
 
     /**
index 4dd37be..651b8d1 100644 (file)
@@ -958,7 +958,7 @@ class backup_gradebook_structure_step extends backup_structure_step {
         $grade_category   = new backup_nested_element('grade_category', array('id'), array(
                 //'courseid',
                 'parent', 'depth', 'path', 'fullname', 'aggregation', 'keephigh',
-                'droplow', 'aggregateonlygraded', 'aggregateoutcomes', 'aggregatesubcats',
+                'droplow', 'aggregateonlygraded', 'aggregateoutcomes',
                 'timecreated', 'timemodified', 'hidden'));
 
         $letters = new backup_nested_element('grade_letters');
index 5492497..3035c7e 100644 (file)
@@ -282,6 +282,11 @@ class restore_gradebook_structure_step extends restore_structure_step {
             }
         }
 
+        // Add a warning about a removed setting.
+        if (!empty($data->aggregatesubcats)) {
+            set_config('show_aggregatesubcats_upgrade_' . $data->courseid, 1);
+        }
+
         //need to insert a course category
         if (empty($newitemid)) {
             $newitemid = $DB->insert_record('grade_categories', $data);
index bb937aa..960c9ec 100644 (file)
@@ -38,6 +38,13 @@ require_once($CFG->libdir . '/completionlib.php');
  */
 class core_backup_moodle2_testcase extends advanced_testcase {
 
+    /**
+     * Tidy up open files that may be left open.
+     */
+    protected function tearDown() {
+        gc_collect_cycles();
+    }
+
     /**
      * Tests the availability field on modules and sections is correctly
      * backed up and restored.
index e288fe2..f60bf39 100644 (file)
@@ -81,6 +81,14 @@ $output = $PAGE->get_renderer('core', 'badges');
 // Roles that can award this badge.
 $acceptedroles = array_keys($badge->criteria[BADGE_CRITERIA_TYPE_MANUAL]->params);
 
+if (empty($acceptedroles)) {
+    echo $OUTPUT->header();
+    $return = html_writer::link(new moodle_url('recipients.php', array('id' => $badge->id)), $strrecipients);
+    echo $OUTPUT->notification(get_string('notacceptedrole', 'badges', $return));
+    echo $OUTPUT->footer();
+    die();
+}
+
 if (count($acceptedroles) > 1) {
     // If there is more than one role that can award a badge, prompt user to make a selection.
     // If it is an admin, include all accepted roles, otherwise only the ones that current user has in this context.
index 616ba97..fd0ad2e 100644 (file)
@@ -150,6 +150,11 @@ class award_criteria_manual extends award_criteria {
     public function review($userid, $filtered = false) {
         global $DB;
 
+        // Roles should always have a parameter.
+        if (empty($this->params)) {
+            return false;
+        }
+
         // Users were already filtered by criteria completion.
         if ($filtered) {
             return true;
index d277721..209e992 100644 (file)
@@ -31,7 +31,7 @@ Feature: Award badges
     And I expand all fieldsets
     And I set the field "Phone" to "123456789"
     And I press "Update profile"
-    And I follow "My badges"
+    And I navigate to "My badges" node in "My profile"
     Then I should see "Profile Badge"
     And I should not see "There are no badges available."
 
@@ -64,8 +64,7 @@ Feature: Award badges
     Then I should see "Recipients (2)"
     And I log out
     And I log in as "student"
-    And I expand "My profile" node
-    And I follow "My badges"
+    And I navigate to "My badges" node in "My profile"
     Then I should see "Site Badge"
 
   @javascript
@@ -109,8 +108,7 @@ Feature: Award badges
     And I log out
     And I log in as "student1"
     And I follow "Course 1"
-    And I expand "My profile" node
-    And I follow "My badges"
+    And I navigate to "My badges" node in "My profile"
     Then I should see "Course Badge"
 
   @javascript
@@ -158,14 +156,12 @@ Feature: Award badges
     And I log out
     And I log in as "student1"
     And I follow "Course 1"
-    And I expand "My profile" node
-    And I follow "My badges"
+    And I navigate to "My badges" node in "My profile"
     Then I should see "There are no badges available."
     And I follow "Home"
     And I follow "Course 1"
     And I press "Mark as complete: Test assignment name"
-    And I expand "My profile" node
-    And I follow "My badges"
+    And I navigate to "My badges" node in "My profile"
     Then I should see "Course Badge"
 
   @javascript
@@ -219,8 +215,7 @@ Feature: Award badges
     And I log out
     And I log in as "student1"
     And I follow "Course 1"
-    And I expand "My profile" node
-    And I follow "My badges"
+    And I navigate to "My badges" node in "My profile"
     Then I should see "There are no badges available."
     And I follow "Home"
     And I follow "Course 1"
@@ -237,6 +232,5 @@ Feature: Award badges
     And I am on homepage
     And I log out
     And I log in as "student1"
-    And I expand "My profile" node
-    And I follow "My badges"
+    And I navigate to "My badges" node in "My profile"
     Then I should see "Course Badge"
index ce97602..6a46c36 100644 (file)
@@ -294,12 +294,12 @@ class block_recent_activity extends block_base {
                 if (!isset($modinfo->instances[$modname][$instanceid])) {
                     continue;
                 }
-                $entry['cmid'] = $modinfo->instances[$modname][$instanceid]->id;
                 if ($log->action == 'add mod') {
                     $entry['action'] = 0;
                 } else {
                     $entry['action'] = 1;
                 }
+                $entry['cmid'] = $modinfo->instances[$modname][$instanceid]->id;
             }
             $entries[] = $entry;
         }
index 97f2ca8..a84e3d1 100644 (file)
@@ -128,7 +128,7 @@ class block_site_main_menu extends block_list {
                 } else {
                     $editbuttons = '';
                 }
-                if ($mod->visible || has_capability('moodle/course:viewhiddenactivities', $context)) {
+                if ($mod->visible || has_capability('moodle/course:viewhiddenactivities', $mod->context)) {
                     if ($ismoving) {
                         if ($mod->id == $USER->activitycopy) {
                             continue;
index 5e127d8..6c6971b 100644 (file)
@@ -130,7 +130,7 @@ class block_social_activities extends block_list {
                 } else {
                     $editbuttons = '';
                 }
-                if ($mod->visible || has_capability('moodle/course:viewhiddenactivities', $context)) {
+                if ($mod->visible || has_capability('moodle/course:viewhiddenactivities', $mod->context)) {
                     if ($ismoving) {
                         if ($mod->id == $USER->activitycopy) {
                             continue;
@@ -169,5 +169,3 @@ class block_social_activities extends block_list {
         return $this->content;
     }
 }
-
-
index f75d8c5..25a7d5a 100644 (file)
@@ -302,16 +302,19 @@ class cachestore_memcached extends cache_store implements cache_is_configurable
      *      be set to false.
      */
     public function get_many($keys) {
+        $return = array();
         $result = $this->connection->getMulti($keys);
         if (!is_array($result)) {
             $result = array();
         }
         foreach ($keys as $key) {
             if (!array_key_exists($key, $result)) {
-                $result[$key] = false;
+                $return[$key] = false;
+            } else {
+                $return[$key] = $result[$key];
             }
         }
-        return $result;
+        return $return;
     }
 
     /**
index 4405da4..e4d51ec 100644 (file)
@@ -556,6 +556,9 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
         }
 
         $store = new cachestore_mongodb('Test mongodb', $configuration);
+        if (!$store->is_ready()) {
+            return false;
+        }
         $store->initialise($definition);
 
         return $store;
@@ -581,6 +584,9 @@ class cachestore_mongodb extends cache_store implements cache_is_configurable {
         $configuration['usesafe'] = 1;
 
         $store = new cachestore_mongodb('Test mongodb', $configuration);
+        if (!$store->is_ready()) {
+            return false;
+        }
         $store->initialise($definition);
 
         return $store;
index 676b26d..b435842 100644 (file)
@@ -318,9 +318,9 @@ function calendar_get_mini($courses, $groups, $users, $calmonth = false, $calyea
     }
 
     // Now display all the calendar
-    $daytime = $display->tstart - DAYSECS;
+    $daytime = strtotime('-1 day', $display->tstart);
     for($day = 1; $day <= $display->maxdays; ++$day, ++$dayweek) {
-        $daytime += DAYSECS;
+        $daytime = strtotime('+1 day', $daytime);
         if($dayweek > $display->maxwday) {
             // We need to change week (table row)
             $content .= '</tr><tr>';
@@ -932,8 +932,8 @@ function calendar_top_controls($type, $data) {
         case 'day':
             $days = calendar_get_days();
 
-            $prevtimestamp = $time - DAYSECS;
-            $nexttimestamp = $time + DAYSECS;
+            $prevtimestamp = strtotime('-1 day', $time);
+            $nexttimestamp = strtotime('+1 day', $time);
 
             $prevdate = $calendartype->timestamp_to_date_array($prevtimestamp);
             $nextdate = $calendartype->timestamp_to_date_array($nexttimestamp);
@@ -1679,7 +1679,7 @@ function calendar_format_event_time($event, $now, $linkparams = null, $usecommon
             $timeend = calendar_time_representation($event->timestart + $event->timeduration);
 
             // Set printable representation.
-            if ($now >= $usermidnightstart && $now < ($usermidnightstart + DAYSECS)) {
+            if ($now >= $usermidnightstart && $now < strtotime('+1 day', $usermidnightstart)) {
                 $url = calendar_get_link_href(new moodle_url(CALENDAR_URL . 'view.php', $linkparams), 0, 0, 0, $endtime);
                 $eventtime = $timestart . ' <strong>&raquo;</strong> ' . html_writer::link($url, $dayend) . $timeend;
             } else {
@@ -2775,7 +2775,7 @@ class calendar_information {
      * @return int tomorrow timestamp
      */
     public function timestamp_tomorrow() {
-        return $this->time + DAYSECS;
+        return strtotime('+1 day', $this->time);
     }
     /**
      * Adds the pretend blocks for the calendar
@@ -2928,7 +2928,7 @@ function calendar_add_icalendar_event($event, $courseid, $subscriptionid, $timez
             $timezone;
     $eventrecord->timestart = strtotime($event->properties['DTSTART'][0]->value . ' ' . $tz);
     if (empty($event->properties['DTEND'])) {
-        $eventrecord->timeduration = 3600; // one hour if no end time specified
+        $eventrecord->timeduration = 0; // no duration if no end time specified
     } else {
         $endtz = isset($event->properties['DTEND'][0]->parameters['TZID']) ? $event->properties['DTEND'][0]->parameters['TZID'] :
                 $timezone;
index 8f0c7a5..91e7a48 100644 (file)
@@ -498,9 +498,9 @@ class core_calendar_renderer extends plugin_renderer_base {
             $weekend = intval($CFG->calendar_weekend);
         }
 
-        $daytime = $display->tstart - DAYSECS;
+        $daytime = strtotime('-1 day', $display->tstart);
         for ($day = 1; $day <= $display->maxdays; ++$day, ++$dayweek) {
-            $daytime = $daytime + DAYSECS;
+            $daytime = strtotime('+1 day', $daytime);
             if($dayweek > $display->maxwday) {
                 // We need to change week (table row)
                 $table->data[] = $row;
index dfe2970..4c9289b 100644 (file)
@@ -69,8 +69,7 @@ class format_singleactivity extends format_base {
     public function extend_course_navigation($navigation, navigation_node $node) {
         // Display orphaned activities for the users who can see them.
         $context = context_course::instance($this->courseid);
-        if (has_all_capabilities(array('moodle/course:viewhiddensections',
-                'moodle/course:viewhiddenactivities'), $context)) {
+        if (has_capability('moodle/course:viewhiddensections', $context)) {
             $modinfo = get_fast_modinfo($this->courseid);
             if (!empty($modinfo->sections[1])) {
                 $section1 = $modinfo->get_section_info(1);
@@ -80,7 +79,9 @@ class format_singleactivity extends format_base {
                 $orphanednode->nodetype = navigation_node::NODETYPE_BRANCH;
                 $orphanednode->add_class('orphaned');
                 foreach ($modinfo->sections[1] as $cmid) {
-                    $this->navigation_add_activity($orphanednode, $modinfo->cms[$cmid]);
+                    if (has_capability('moodle/course:viewhiddenactivities', context_module::instance($cmid))) {
+                        $this->navigation_add_activity($orphanednode, $modinfo->cms[$cmid]);
+                    }
                 }
             }
         }
index 2cca5c7..3247db4 100644 (file)
@@ -78,7 +78,7 @@ if (!empty($add)) {
     $returntomod = optional_param('return', 0, PARAM_BOOL);
     redirect("$CFG->wwwroot/course/modedit.php?update=$update&return=$returntomod&sr=$sectionreturn");
 
-} else if (!empty($duplicate)) {
+} else if (!empty($duplicate) and confirm_sesskey()) {
      $cm     = get_coursemodule_from_id('', $duplicate, 0, true, MUST_EXIST);
      $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);