diff --git a/classes/event/attempt_submitted.php b/classes/event/attempt_submitted.php
new file mode 100644
index 0000000000000000000000000000000000000000..8392b2469d4f9550457ccae5ec81d468c29e0689
--- /dev/null
+++ b/classes/event/attempt_submitted.php
@@ -0,0 +1,46 @@
+<?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/>.
+
+/**
+ * Attempt submitted event
+ *
+ * @package mod_hvp
+ * @copyright 2020 Joubel AS <contact@joubel.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace mod_hvp\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The mod_hvp instance list viewed event class.
+ *
+ * @package mod_hvp
+ * @copyright @copyright 2016 Joubel AS <contact@joubel.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class attempt_submitted extends \core\event\base
+{
+
+ /**
+ * @inheritDoc
+ */
+ protected function init() {
+ $this->data['crud'] = 'u';
+ $this->data['edulevel'] = self::LEVEL_PARTICIPATING;
+ }
+}
diff --git a/classes/user_grades.php b/classes/user_grades.php
index 103ea6db39a3b06e343a83f5010c18344620aa81..eca660a53fffd6286bc1b2068ccc31713fee2701 100644
--- a/classes/user_grades.php
+++ b/classes/user_grades.php
@@ -96,6 +96,12 @@ class user_grades {
$content->name, $content->major_version . '.' . $content->minor_version
);
+ // Trigger Moodle event for async notification messages
+ $event = \mod_hvp\event\attempt_submitted::create([
+ 'context' => $context,
+ ]);
+ $event->trigger();
+
\H5PCore::ajaxSuccess();
}
diff --git a/db/access.php b/db/access.php
index 84757113d3aed7fa107476ec2d8a331b0d4b34e4..5658c6e3f18a34858c7439111a9a92fcabe6d0fb 100644
--- a/db/access.php
+++ b/db/access.php
@@ -173,4 +173,18 @@ $capabilities = array(
)
),
+ // Receive a confirmation message of own h5p submission.
+ 'mod/hvp:emailconfirmsubmission' => array(
+ 'captype' => 'read',
+ 'contextlevel' => CONTEXT_MODULE,
+ 'archetypes' => array()
+ ),
+
+ // Receive a notification message of other peoples' h5p submissions.
+ 'mod/hvp:emailnotifysubmission' => array(
+ 'captype' => 'read',
+ 'contextlevel' => CONTEXT_MODULE,
+ 'archetypes' => array()
+ ),
+
);
diff --git a/db/events.php b/db/events.php
new file mode 100644
index 0000000000000000000000000000000000000000..c6f7983bf08934a3d025dc600068932fd531ce3f
--- /dev/null
+++ b/db/events.php
@@ -0,0 +1,38 @@
+<?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/>.
+
+/**
+ * Add event handlers for H5P
+ *
+ * @package mod_hvp
+ * @category event
+ * @copyright 2020 Joubel AS <contact@joubel.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+defined('MOODLE_INTERNAL') || die();
+
+$observers = array(
+
+ // Handle attempt submitted event, as a way to send confirmation messages asynchronously.
+ array(
+ 'eventname' => '\mod_hvp\event\attempt_submitted',
+ 'includefile' => '/mod/hvp/locallib.php',
+ 'callback' => 'hvp_attempt_submitted_handler',
+ 'internal' => false
+ ),
+);
diff --git a/db/messages.php b/db/messages.php
new file mode 100644
index 0000000000000000000000000000000000000000..a08d8f0d56f009f42ece8d954c76393312cd1ed4
--- /dev/null
+++ b/db/messages.php
@@ -0,0 +1,40 @@
+<?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/>.
+
+/**
+ * Defines message providers (types of message sent) for the hvp module.
+ *
+ * @package mod_hvp
+ * @copyright 2020 Joubel AS <contact@joubel.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$messageproviders = array(
+ // Notify teacher that a student has submitted an attempt.
+ 'submission' => array(
+ 'capability' => 'mod/hvp:emailnotifysubmission'
+ ),
+
+ // Confirm a student's quiz attempt.
+ 'confirmation' => array(
+ 'capability' => 'mod/hvp:emailconfirmsubmission',
+ 'defaults' => array(
+ 'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
+ ),
+ ),
+);
diff --git a/lang/en/hvp.php b/lang/en/hvp.php
index 7eaa5755b0d4c0916f4a56556157f2524bfe70d3..ce26356cae3313d45e9937fedbba0b7159358a4f 100644
--- a/lang/en/hvp.php
+++ b/lang/en/hvp.php
@@ -225,6 +225,8 @@ $string['hvp:userestrictedlibraries'] = 'Use restricted H5P content types';
$string['hvp:updatelibraries'] = 'Install new H5P content types or update existing ones';
$string['hvp:getcachedassets'] = 'Required for viewing H5P activities';
$string['hvp:installrecommendedh5plibraries'] = 'Install new safe H5P content types recommended by H5P.org';
+$string['hvp:emailconfirmsubmission'] = 'Get a confirmation message when submitting';
+$string['hvp:emailnotifysubmission'] = 'Get a notification message when an attempt is submitted';
// Capabilities error messages.
$string['nopermissiontogettranslations'] = 'You do not have permissions to retrieve translations';
@@ -448,4 +450,24 @@ $string['unpackedfilesexceedsmaxsize'] = 'The total size of the unpacked files e
$string['couldnotreadfilefromzip'] = 'Unable to read file from the package: %fileName';
$string['couldnotparsejsonfromzip'] = 'Unable to parse JSON from the package: %fileName';
$string['couldnotparsepostdata'] = 'Could not parse post data.';
-$string['nombstringexteension'] = 'The mbstring PHP extension is not loaded. H5P needs this to function properly';
\ No newline at end of file
+$string['nombstringexteension'] = 'The mbstring PHP extension is not loaded. H5P needs this to function properly';
+
+// Messaging api
+$string['messageprovider:confirmation'] = 'Confirmation of your own H5P submissions';
+$string['messageprovider:submission'] = 'Notification of H5P submissions';
+$string['emailnotifysubject'] = '{$a->studentname} has completed {$a->hvpname}';
+$string['emailnotifybody'] = 'Hi {$a->username},
+
+{$a->studentname} has completed \'{$a->hvpname}\' ({$a->hvpurl}) in course \'{$a->coursename}\'.
+
+You can review this attempt at {$a->hvpreporturl}.';
+$string['emailnotifysmall'] = '{$a->studentname} has completed {$a->hvpname}. See {$a->hvpreporturl}';
+$string['emailconfirmbody'] = 'Hi {$a->username},
+
+Thank you for submitting your answers to \'{$a->hvpname}\' in course \'{$a->coursename}\'.
+
+This message confirms that your answers have been saved.
+
+You can access this H5P at {$a->hvpurl}.';
+$string['emailconfirmsmall'] = 'Thank you for submitting your answers to \'{$a->hvpname}\'';
+$string['emailconfirmsubject'] = 'Submission confirmation: {$a->hvpname}';
diff --git a/locallib.php b/locallib.php
index 72f7eee24911a3c90859d9282dbcb0744bc7643b..f75e4d344ad687d1e46070e57bbc9fe495980413 100644
--- a/locallib.php
+++ b/locallib.php
@@ -23,6 +23,9 @@
* @copyright 2016 Joubel AS <contact@joubel.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
+
+use core\message\message;
+
defined('MOODLE_INTERNAL') || die();
require_once('autoloader.php');
@@ -459,3 +462,192 @@ function hvp_require_view_results_permission($userid, $context, $redirectcontent
}
}
}
+
+/**
+ * Sends notification messages to the interested parties that assign the role capability
+ *
+ * @param object $recipient user object of the intended recipient
+ * @param $submitter
+ * @param object $a associative array of replaceable fields for the templates
+ *
+ * @return int|false as for {@link message_send()}.
+ * @throws coding_exception
+ */
+function hvp_send_notification($recipient, $submitter, $a) {
+ // Recipient info for template.
+ $a->useridnumber = $recipient->id;
+ $a->username = fullname($recipient);
+ $a->userusername = $recipient->username;
+
+ // Prepare the message.
+ $message = new message();
+ $message->component = 'mod_hvp';
+ $message->name = 'submission';
+ $message->userfrom = $submitter;
+ $message->userto = $recipient;
+ $message->subject = get_string('emailnotifysubject', 'hvp', $a);
+ $message->fullmessage = get_string('emailnotifybody', 'hvp', $a);
+ $message->fullmessageformat = FORMAT_PLAIN;
+ $message->fullmessagehtml = '';
+ $message->smallmessage = get_string('emailnotifysmall', 'hvp', $a);
+ $message->courseid = $a->courseid;
+
+ $message->contexturl = $a->hvpreporturl;
+ $message->contexturlname = $a->hvpname;
+
+ return message_send($message);
+}
+
+/**
+ * Sends a confirmation message to the student confirming that the attempt was processed.
+ *
+ * @param object $a useful information that can be used in the message
+ * subject and body.
+ *
+ * @return int|false as for {@link message_send()}.
+ * @throws coding_exception
+ */
+function hvp_send_confirmation($recipient, $a) {
+ // Add information about the recipient to $a.
+ $a->username = fullname($recipient);
+ $a->userusername = $recipient->username;
+
+ // Prepare the message.
+ $eventdata = new \core\message\message();
+ $eventdata->courseid = $a->courseid;
+ $eventdata->component = 'mod_hvp';
+ $eventdata->name = 'confirmation';
+ $eventdata->notification = 1;
+
+ $eventdata->userfrom = core_user::get_noreply_user();
+ $eventdata->userto = $recipient;
+ $eventdata->subject = get_string('emailconfirmsubject', 'hvp', $a);
+ $eventdata->fullmessage = get_string('emailconfirmbody', 'hvp', $a);
+ $eventdata->fullmessageformat = FORMAT_PLAIN;
+ $eventdata->fullmessagehtml = '';
+
+ $eventdata->smallmessage = get_string('emailconfirmsmall', 'hvp', $a);
+ $eventdata->contexturl = $a->hvpurl;
+ $eventdata->contexturlname = $a->hvpname;
+
+ return message_send($eventdata);
+}
+
+/**
+ * Send all the required messages when a h5p attempt is submitted.
+ *
+ * @param object $course the course
+ * @param object $hvp the h5p
+ * @param object $attempt this attempt just finished
+ * @param context $context the h5p context
+ * @param object $cm the coursemodule for this h5p
+ *
+ * @return bool true if all necessary messages were sent successfully, else false.
+ * @throws coding_exception
+ * @throws dml_exception
+ */
+function hvp_send_notification_messages($course, $hvp, $attempt, $context, $cm) {
+ global $CFG, $DB;
+
+ // Do nothing if required objects not present.
+ if (empty($course) or empty($hvp) or empty($attempt) or empty($context)) {
+ throw new coding_exception('$course, $hvp, $attempt, $context and $cm must all be set.');
+ }
+
+ $submitter = $DB->get_record('user', array('id' => $attempt->userid), '*', MUST_EXIST);
+
+ // Check for confirmation required.
+ $sendconfirm = false;
+ $notifyexcludeusers = '';
+ if (has_capability('mod/hvp:emailconfirmsubmission', $context, $submitter, false)) {
+ $notifyexcludeusers = $submitter->id;
+ $sendconfirm = true;
+ }
+
+ // Check for notifications required.
+ $notifyfields = 'u.id, u.username, u.idnumber, u.email, u.emailstop, u.lang,
+ u.timezone, u.mailformat, u.maildisplay, u.auth, u.suspended, u.deleted, ';
+ $notifyfields .= get_all_user_name_fields(true, 'u');
+ $groups = groups_get_all_groups($course->id, $submitter->id, $cm->groupingid);
+ if (is_array($groups) && count($groups) > 0) {
+ $groups = array_keys($groups);
+ } else if (groups_get_activity_groupmode($cm, $course) != NOGROUPS) {
+ // If the user is not in a group, and the hvp is set to group mode,
+ // then set $groups to a non-existant id so that only users with
+ // 'moodle/site:accessallgroups' get notified.
+ $groups = - 1;
+ } else {
+ $groups = '';
+ }
+ $userstonotify = get_users_by_capability($context, 'mod/hvp:emailnotifysubmission',
+ $notifyfields, '', '', '', $groups, $notifyexcludeusers, false, false, true);
+
+ if (empty($userstonotify) && !$sendconfirm) {
+ return true; // Nothing to do.
+ }
+
+ $a = new stdClass();
+ // Course info.
+ $a->courseid = $course->id;
+ $a->coursename = $course->fullname;
+ $a->courseshortname = $course->shortname;
+
+ // H5P info.
+ $a->hvpname = $hvp->name;
+ $report = "{$CFG->wwwroot}/mod/hvp/review.php?id={$hvp->id}&course={$course->id}&user={$submitter->id}";
+ $a->hvpreporturl = $report;
+ $a->hvpreportlink = '<a href="' . $a->hvpreporturl . '">' .
+ format_string($hvp->name, true, ['context' => $context]) . ' report</a>';
+ $a->hvpurl = $CFG->wwwroot . '/mod/hvp/view.php?id=' . $cm->id;
+ $a->hvplink = '<a href="' . $a->hvpurl . '">' .
+ format_string($hvp->name, true, ['context' => $context]) . '</a>';
+ $a->hvpid = $hvp->id;
+ $a->hvpcmid = $cm->id;
+
+ // Student who sat the hvp info.
+ $a->studentidnumber = $submitter->id;
+ $a->studentname = fullname($submitter);
+ $a->studentusername = $submitter->username;
+
+ $allok = true;
+
+ // Send notifications if required.
+ if (!empty($userstonotify)) {
+ foreach ($userstonotify as $recipient) {
+ $allok = $allok && hvp_send_notification($recipient, $submitter, $a);
+ }
+ }
+
+ // Send confirmation if required. We send the student confirmation last, so
+ // that if message sending is being intermittently buggy, which means we send
+ // some but not all messages, and then try again later, then teachers may get
+ // duplicate messages, but the student will always get exactly one.
+ if ($sendconfirm) {
+ $allok = $allok && hvp_send_confirmation($submitter, $a);
+ }
+
+ return $allok;
+}
+
+/**
+ * Callback for the attempt_submitted event.
+ * Sends out notification messages.
+ *
+ * @param $event
+ *
+ * @throws coding_exception
+ * @throws dml_exception
+ */
+function hvp_attempt_submitted_handler($event) {
+ global $DB, $PAGE;
+ $course = $DB->get_record('course', array('id' => $event->courseid));
+ $cm = get_coursemodule_from_id('hvp', $event->get_context()->instanceid, $event->courseid);
+ $hvp = $DB->get_record('hvp', array('id' => $cm->instance));
+ $attempt = (object) [
+ 'userid' => $event->userid
+ ];
+ $context = context_module::instance($cm->id);
+ $PAGE->set_context($context);
+
+ hvp_send_notification_messages($course, $hvp, $attempt, $context, $cm);
+}
\ No newline at end of file
diff --git a/version.php b/version.php
index b4b69751dcedee61431601b5523b1b9bbbdad215..90d9ba2d7804730d68a2a20daa66d50e137dc2ab 100644
--- a/version.php
+++ b/version.php
@@ -23,7 +23,7 @@
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2019111300;
+$plugin->version = 2020013103;
$plugin->requires = 2013051403;
$plugin->cron = 0;
$plugin->component = 'mod_hvp';