Skip to content

Commit

Permalink
MDL-60680 notifications: Return custom data in notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
jleyva committed Apr 25, 2019
1 parent 26e778d commit 36fa0ec
Show file tree
Hide file tree
Showing 18 changed files with 325 additions and 15 deletions.
18 changes: 17 additions & 1 deletion badges/tests/badgeslib_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -290,13 +290,29 @@ public function test_delete_badge_criteria() {
}

public function test_badge_awards() {
global $DB;
$this->preventResetByRollback(); // Messaging is not compatible with transactions.
$badge = new badge($this->badgeid);
$user1 = $this->getDataGenerator()->create_user();

$badge->issue($user1->id, true);
$sink = $this->redirectMessages();

$DB->set_field_select('message_processors', 'enabled', 0, "name <> 'email'");
set_user_preference('message_provider_moodle_badgerecipientnotice_loggedoff', 'email', $user1);

$badge->issue($user1->id, false);
$this->assertDebuggingCalled(); // Expect debugging while baking a badge via phpunit.
$this->assertTrue($badge->is_issued($user1->id));

$messages = $sink->get_messages();
$sink->close();
$this->assertCount(1, $messages);
$message = array_pop($messages);
// Check we have the expected data.
$customdata = json_decode($message->customdata);
$this->assertObjectHasAttribute('notificationiconurl', $customdata);
$this->assertObjectHasAttribute('hash', $customdata);

$user2 = $this->getDataGenerator()->create_user();
$badge->issue($user2->id, true);
$this->assertTrue($badge->is_issued($user2->id));
Expand Down
14 changes: 13 additions & 1 deletion competency/lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
* @return array
*/
function core_competency_comment_add($comment, $params) {
global $USER;
global $USER, $PAGE;

if (!get_config('core_competency', 'enabled')) {
return;
Expand Down Expand Up @@ -132,10 +132,16 @@ function core_competency_comment_add($comment, $params) {
$message->contexturl = $url->out(false);
$message->contexturlname = $urlname;

$userpicture = new \user_picture($user);
// Message each recipient.
foreach ($recipients as $recipient) {
$msgcopy = clone($message);
$msgcopy->userto = $recipient;
// Generate an out-of-session token for the user receiving the message.
$userpicture->includetoken = $recipient;
$msgcopy->customdata = [
'notificationiconurl' => $userpicture->get_url($PAGE)->out(false),
];
message_send($msgcopy);
}

Expand Down Expand Up @@ -201,10 +207,16 @@ function core_competency_comment_add($comment, $params) {
$message->contexturl = $url->out(false);
$message->contexturlname = $urlname;

$userpicture = new \user_picture($user);
// Message each recipient.
foreach ($recipients as $recipient) {
$msgcopy = clone($message);
$msgcopy->userto = $recipient;
// Generate an out-of-session token for the user receiving the message.
$userpicture->includetoken = $recipient;
$msgcopy->customdata = [
'notificationiconurl' => $userpicture->get_url($PAGE)->out(false),
];
message_send($msgcopy);
}
}
Expand Down
14 changes: 12 additions & 2 deletions competency/tests/lib_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@
class core_competency_lib_testcase extends advanced_testcase {

public function test_comment_add_user_competency() {
global $DB;
global $DB, $PAGE;
$this->resetAfterTest();
$dg = $this->getDataGenerator();
$lpg = $dg->get_plugin_generator('core_competency');

$u1 = $dg->create_user();
$u1 = $dg->create_user(['picture' => 1]);
$u2 = $dg->create_user();
$u3 = $dg->create_user();
$reviewerroleid = $dg->create_role();
Expand Down Expand Up @@ -96,6 +96,13 @@ public function test_comment_add_user_competency() {
$this->assertEquals(FORMAT_MOODLE, $message->fullmessageformat);
$this->assertEquals($expectedurl->out(false), $message->contexturl);
$this->assertEquals($expectedurlname, $message->contexturlname);
// Test customdata.
$customdata = json_decode($message->customdata);
$this->assertObjectHasAttribute('notificationiconurl', $customdata);
$this->assertContains('tokenpluginfile.php', $customdata->notificationiconurl);
$userpicture = new \user_picture($u1);
$userpicture->includetoken = $u2->id;
$this->assertEquals($userpicture->get_url($PAGE)->out(false), $customdata->notificationiconurl);

// Reviewer posts a comment for the user competency being in two plans. Owner is messaged.
$this->setUser($u2);
Expand Down Expand Up @@ -218,6 +225,9 @@ public function test_comment_add_plan() {
$message = array_pop($messages);
$this->assertEquals(core_user::get_noreply_user()->id, $message->useridfrom);
$this->assertEquals($u1->id, $message->useridto);
// Test customdata.
$customdata = json_decode($message->customdata);
$this->assertObjectHasAttribute('notificationiconurl', $customdata);

// Post a comment in a plan with reviewer. The reviewer is messaged.
$p1->set('reviewerid', $u2->id);
Expand Down
10 changes: 10 additions & 0 deletions lib/badgeslib.php
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,11 @@ function badges_notify_badge_award(badge $badge, $userid, $issued, $filepathhash
$eventdata->fullmessageformat = FORMAT_HTML;
$eventdata->fullmessagehtml = $message;
$eventdata->smallmessage = '';
$eventdata->customdata = [
'notificationiconurl' => moodle_url::make_pluginfile_url(
$badge->get_context()->id, 'badges', 'badgeimage', $badge->id, '/', 'f1')->out(),
'hash' => $issued,
];

// Attach badge image if possible.
if (!empty($CFG->allowattachments) && $badge->attachment && is_string($filepathhash)) {
Expand Down Expand Up @@ -1049,6 +1054,11 @@ function badges_notify_badge_award(badge $badge, $userid, $issued, $filepathhash
$eventdata->fullmessageformat = FORMAT_HTML;
$eventdata->fullmessagehtml = $creatormessage;
$eventdata->smallmessage = '';
$eventdata->customdata = [
'notificationiconurl' => moodle_url::make_pluginfile_url(
$badge->get_context()->id, 'badges', 'badgeimage', $badge->id, '/', 'f1')->out(),
'hash' => $issued,
];

message_send($eventdata);
$DB->set_field('badge_issued', 'issuernotified', time(), array('badgeid' => $badge->id, 'userid' => $userid));
Expand Down
8 changes: 8 additions & 0 deletions lib/classes/message/manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,14 @@ public static function send_message_to_conversation(message $eventdata, \stdClas

// Spoof the userto based on the current member id.
$localisedeventdata->userto = $recipient;
// Check if the notification is including images that will need a user token to be displayed outside Moodle.
if (!empty($localisedeventdata->customdata)) {
$customdata = json_decode($localisedeventdata->customdata);
if (is_object($customdata) && !empty($customdata->notificationiconurl)) {
$customdata->tokenpluginfile = get_user_key('core_files', $localisedeventdata->userto->id);
$localisedeventdata->customdata = $customdata; // Message class will JSON encode again.
}
}

$s = new \stdClass();
$s->sitename = format_string($SITE->shortname, true, array('context' => \context_course::instance(SITEID)));
Expand Down
29 changes: 26 additions & 3 deletions message/classes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -1887,7 +1887,7 @@ public static function can_send_message_to_conversation(int $userid, int $conver
*/
public static function send_message_to_conversation(int $userid, int $conversationid, string $message,
int $format) : \stdClass {
global $DB;
global $DB, $PAGE;

if (!self::can_send_message_to_conversation($userid, $conversationid)) {
throw new \moodle_exception("User $userid cannot send a message to conversation $conversationid");
Expand All @@ -1897,7 +1897,7 @@ public static function send_message_to_conversation(int $userid, int $conversati
$eventdata->courseid = 1;
$eventdata->component = 'moodle';
$eventdata->name = 'instantmessage';
$eventdata->userfrom = $userid;
$eventdata->userfrom = \core_user::get_user($userid);
$eventdata->convid = $conversationid;

if ($format == FORMAT_HTML) {
Expand All @@ -1915,6 +1915,24 @@ public static function send_message_to_conversation(int $userid, int $conversati

$eventdata->timecreated = time();
$eventdata->notification = 0;

$conv = $DB->get_record('message_conversations', ['id' => $conversationid]);
if ($conv->type == self::MESSAGE_CONVERSATION_TYPE_GROUP) {
$convextrafields = self::get_linked_conversation_extra_fields([$conv]);
// Conversation image.
$imageurl = isset($convextrafields[$conv->id]) ? $convextrafields[$conv->id]['imageurl'] : null;
if ($imageurl) {
$eventdata->customdata = [
'notificationiconurl' => $imageurl,
];
}
} else if ($conv->type == self::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL) {
$userpicture = new \user_picture($eventdata->userfrom);
$eventdata->customdata = [
'notificationiconurl' => $userpicture->get_url($PAGE)->out(false),
];
}

$messageid = message_send($eventdata);

$messagerecord = $DB->get_record('messages', ['id' => $messageid], 'id, useridfrom, fullmessage,
Expand Down Expand Up @@ -2511,7 +2529,7 @@ public static function can_create_contact(int $userid, int $requesteduserid) : b
* @return \stdClass the request
*/
public static function create_contact_request(int $userid, int $requesteduserid) : \stdClass {
global $DB;
global $DB, $PAGE;

$request = new \stdClass();
$request->userid = $userid;
Expand Down Expand Up @@ -2542,6 +2560,11 @@ public static function create_contact_request(int $userid, int $requesteduserid)
$message->fullmessagehtml = $fullmessage;
$message->smallmessage = '';
$message->contexturl = $url->out(false);
$userpicture = new \user_picture($userfrom);
$userpicture->includetoken = $userto->id; // Generate an out-of-session token for the user receiving the message.
$message->customdata = [
'notificationiconurl' => $userpicture->get_url($PAGE)->out(false),
];

message_send($message);

Expand Down
8 changes: 7 additions & 1 deletion message/lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ function message_format_contexturl($message) {
* @return int|false the ID of the new message or false
*/
function message_post_message($userfrom, $userto, $message, $format) {
global $SITE, $CFG, $USER;
global $PAGE;

$eventdata = new \core\message\message();
$eventdata->courseid = 1;
Expand All @@ -351,6 +351,12 @@ function message_post_message($userfrom, $userto, $message, $format) {
$eventdata->smallmessage = $message;//store the message unfiltered. Clean up on output.
$eventdata->timecreated = time();
$eventdata->notification = 0;
// User image.
$userpicture = new user_picture($userfrom);
$userpicture->includetoken = $userto->id; // Generate an out-of-session token for the user receiving the message.
$eventdata->customdata = [
'notificationiconurl' => $userpicture->get_url($PAGE)->out(false),
];
return message_send($eventdata);
}

Expand Down
74 changes: 73 additions & 1 deletion message/tests/api_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -4753,7 +4753,13 @@ public function test_create_contact_request() {
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();

$sink = $this->redirectMessages();
$request = \core_message\api::create_contact_request($user1->id, $user2->id);
$messages = $sink->get_messages();
$sink->close();
// Test customdata.
$customdata = json_decode($messages[0]->customdata);
$this->assertObjectHasAttribute('notificationiconurl', $customdata);

$this->assertEquals($user1->id, $request->userid);
$this->assertEquals($user2->id, $request->requesteduserid);
Expand Down Expand Up @@ -5777,8 +5783,13 @@ public function test_send_message_to_conversation_individual_conversation() {

// Send a message to an individual conversation.
$sink = $this->redirectEvents();
$messagesSink = $this->redirectMessages();
$message1 = \core_message\api::send_message_to_conversation($user1->id, $ic1->id, 'this is a message', FORMAT_MOODLE);
$events = $sink->get_events();
$messages = $messagesSink->get_messages();
// Test customdata.
$customdata = json_decode($messages[0]->customdata);
$this->assertObjectHasAttribute('notificationiconurl', $customdata);

// Verify the message returned.
$this->assertInstanceOf(\stdClass::class, $message1);
Expand Down Expand Up @@ -5818,15 +5829,18 @@ public function test_send_message_to_conversation_group_conversation() {

// Send a message to a group conversation.
$sink = $this->redirectEvents();
$messagesSink = $this->redirectMessages();
$message1 = \core_message\api::send_message_to_conversation($user1->id, $gc2->id, 'message to the group', FORMAT_MOODLE);
$events = $sink->get_events();

$messages = $messagesSink->get_messages();
// Verify the message returned.
$this->assertInstanceOf(\stdClass::class, $message1);
$this->assertObjectHasAttribute('id', $message1);
$this->assertAttributeEquals($user1->id, 'useridfrom', $message1);
$this->assertAttributeEquals('message to the group', 'text', $message1);
$this->assertObjectHasAttribute('timecreated', $message1);
// Test customdata.
$this->assertObjectHasAttribute('customdata', $messages[0]); // No group image means no customdata.

// Verify events. Note: the event is a message read event because of an if (PHPUNIT) conditional within message_send(),
// however, we can still determine the number and ids of any recipients this way.
Expand All @@ -5837,6 +5851,64 @@ public function test_send_message_to_conversation_group_conversation() {
$this->assertContains($user4->id, $userids);
}

/**
* Test verifying that messages can be sent to existing linked group conversations.
*/
public function test_send_message_to_conversation_linked_group_conversation() {
global $CFG;

// Create some users.
$user1 = self::getDataGenerator()->create_user();
$user2 = self::getDataGenerator()->create_user();
$user3 = self::getDataGenerator()->create_user();

$course = $this->getDataGenerator()->create_course();

// Create a group with a linked conversation and a valid image.
$this->setAdminUser();
$this->getDataGenerator()->enrol_user($user1->id, $course->id);
$this->getDataGenerator()->enrol_user($user2->id, $course->id);
$this->getDataGenerator()->enrol_user($user3->id, $course->id);
$group = $this->getDataGenerator()->create_group([
'courseid' => $course->id,
'enablemessaging' => 1,
'picturepath' => $CFG->dirroot . '/lib/tests/fixtures/gd-logo.png'
]);

// Add users to group.
$this->getDataGenerator()->create_group_member(array('groupid' => $group->id, 'userid' => $user1->id));
$this->getDataGenerator()->create_group_member(array('groupid' => $group->id, 'userid' => $user2->id));

// Verify the group with the image works as expected.
$conversations = \core_message\api::get_conversations($user1->id);
$this->assertEquals(2, $conversations[0]->membercount);
$this->assertEquals($course->shortname, $conversations[0]->subname);
$groupimageurl = get_group_picture_url($group, $group->courseid, true);
$this->assertEquals($groupimageurl, $conversations[0]->imageurl);

// Redirect messages.
// This marks messages as read, but we can still observe and verify the number of conversation recipients,
// based on the message_viewed events generated as part of marking the message as read for each user.
$this->preventResetByRollback();
$sink = $this->redirectMessages();

// Send a message to a group conversation.
$messagesSink = $this->redirectMessages();
$message1 = \core_message\api::send_message_to_conversation($user1->id, $conversations[0]->id,
'message to the group', FORMAT_MOODLE);
$messages = $messagesSink->get_messages();
// Verify the message returned.
$this->assertInstanceOf(\stdClass::class, $message1);
$this->assertObjectHasAttribute('id', $message1);
$this->assertAttributeEquals($user1->id, 'useridfrom', $message1);
$this->assertAttributeEquals('message to the group', 'text', $message1);
$this->assertObjectHasAttribute('timecreated', $message1);
// Test customdata.
$customdata = json_decode($messages[0]->customdata);
$this->assertObjectHasAttribute('notificationiconurl', $customdata);
$this->assertEquals($groupimageurl, $customdata->notificationiconurl);;
}

/**
* Test verifying that messages cannot be sent to conversations that don't exist.
*/
Expand Down
16 changes: 15 additions & 1 deletion mod/assign/locallib.php
Original file line number Diff line number Diff line change
Expand Up @@ -6194,7 +6194,7 @@ public static function send_assignment_notification($userfrom,
$assignmentname,
$blindmarking,
$uniqueidforuser) {
global $CFG;
global $CFG, $PAGE;

$info = new stdClass();
if ($blindmarking) {
Expand Down Expand Up @@ -6244,6 +6244,20 @@ public static function send_assignment_notification($userfrom,
$eventdata->notification = 1;
$eventdata->contexturl = $info->url;
$eventdata->contexturlname = $info->assignment;
$customdata = [
'cmid' => $coursemodule->id,
'instance' => $coursemodule->instance,
'messagetype' => $messagetype,
'blindmarking' => $blindmarking,
'uniqueidforuser' => $uniqueidforuser,
];
// Check if the userfrom is real and visible.
if (!empty($userfrom->id) && core_user::is_real_user($userfrom->id)) {
$userpicture = new user_picture($userfrom);
$userpicture->includetoken = $userto->id; // Generate an out-of-session token for the user receiving the message.
$customdata['notificationiconurl'] = $userpicture->get_url($PAGE)->out(false);
}
$eventdata->customdata = $customdata;

message_send($eventdata);
}
Expand Down
Loading

0 comments on commit 36fa0ec

Please sign in to comment.