MDL-60680 notifications: New customdata field

New field to store custom data for message processors.
This commit is contained in:
Juan Leyva 2019-02-05 14:59:28 +01:00
parent c13438158b
commit 333d11c9fc
13 changed files with 94 additions and 6 deletions

View File

@ -52,6 +52,7 @@ defined('MOODLE_INTERNAL') || die();
* replyto string An email address which can be used to send an reply.
* attachment stored_file File instance that needs to be sent as attachment.
* attachname string Name of the attachment.
* customdata mixed Custom data to be passed to the message processor. Must be serialisable using json_encode().
*
* @package core_message
* @since Moodle 2.9
@ -122,9 +123,12 @@ class message {
/** @var int The time the message was created.*/
private $timecreated;
/** @var boolean Mark trust content. */
/** @var boolean Mark trust content. */
private $fullmessagetrust;
/** @var mixed Custom data to be passed to the message processor. Must be serialisable using json_encode(). */
private $customdata;
/** @var array a list of properties that is allowed for each message. */
private $properties = array(
'courseid',
@ -148,8 +152,9 @@ class message {
'attachment',
'attachname',
'timecreated',
'fullmessagetrust'
);
'fullmessagetrust',
'customdata',
);
/** @var array property to store any additional message processor specific content */
private $additionalcontent = array();
@ -199,6 +204,20 @@ class message {
}
}
/**
* Always JSON encode customdata.
*
* @param mixed $customdata a data structure that must be serialisable using json_encode().
*/
protected function set_customdata($customdata) {
// Always include the courseid (because is not stored in the notifications or messages table).
if (!empty($this->courseid) && (is_object($customdata) || is_array($customdata))) {
$customdata = (array) $customdata;
$customdata['courseid'] = $this->courseid;
}
$this->customdata = json_encode($customdata);
}
/**
* Helper method used to get message content added with processor specific content.
*
@ -251,6 +270,12 @@ class message {
* @throws \coding_exception
*/
public function __set($prop, $value) {
// Custom data must be JSON encoded always.
if ($prop == 'customdata') {
return $this->set_customdata($value);
}
if (in_array($prop, $this->properties)) {
return $this->$prop = $value;
}

View File

@ -552,6 +552,7 @@
<FIELD NAME="timeusertodeleted" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="component" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="eventtype" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="customdata" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Custom data to be passed to the message processor. Must be serialisable using json_encode()"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
@ -604,6 +605,7 @@
<FIELD NAME="smallmessage" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="fullmessagetrust" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="customdata" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Custom data to be passed to the message processor. Must be serialisable using json_encode()"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
@ -698,6 +700,7 @@
<FIELD NAME="contexturlname" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="timeread" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="customdata" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Custom data to be passed to the message processor. Must be serialisable using json_encode()"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>

View File

@ -3000,5 +3000,34 @@ function xmldb_main_upgrade($oldversion) {
upgrade_main_savepoint(true, 2019041300.01);
}
if ($oldversion < 2019041800.01) {
// Add new customdata field to message table.
$table = new xmldb_table('message');
$field = new xmldb_field('customdata', XMLDB_TYPE_TEXT, null, null, null, null, null, 'eventtype');
// Conditionally launch add field output.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
// Add new customdata field to notifications and messages table.
$table = new xmldb_table('notifications');
$field = new xmldb_field('customdata', XMLDB_TYPE_TEXT, null, null, null, null, null, 'timecreated');
// Conditionally launch add field output.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
$table = new xmldb_table('messages');
// Conditionally launch add field output.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
// Main savepoint reached.
upgrade_main_savepoint(true, 2019041800.01);
}
return true;
}

View File

@ -153,6 +153,7 @@ function message_send(\core\message\message $eventdata) {
$tabledata->fullmessagehtml = $eventdata->fullmessagehtml;
$tabledata->smallmessage = $eventdata->smallmessage;
$tabledata->timecreated = time();
$tabledata->customdata = $eventdata->customdata;
// The Trusted Content system.
// Texts created or uploaded by such users will be marked as trusted and will not be cleaned before display.
@ -255,6 +256,7 @@ function message_send(\core\message\message $eventdata) {
$tabledata->eventtype = $eventdata->name;
$tabledata->component = $eventdata->component;
$tabledata->timecreated = time();
$tabledata->customdata = $eventdata->customdata;
if (!empty($eventdata->contexturl)) {
$tabledata->contexturl = (string)$eventdata->contexturl;
} else {

View File

@ -202,6 +202,7 @@ class core_messagelib_testcase extends advanced_testcase {
$message->fullmessagehtml = '<p>message body</p>';
$message->smallmessage = 'small message';
$message->notification = '0';
$message->customdata = ['datakey' => 'data'];
$sink = $this->redirectMessages();
$this->setCurrentTimeStart();
@ -218,6 +219,12 @@ class core_messagelib_testcase extends advanced_testcase {
$this->assertEquals($message->smallmessage, $savedmessage->smallmessage);
$this->assertEquals($message->smallmessage, $savedmessage->smallmessage);
$this->assertEquals($message->notification, $savedmessage->notification);
$this->assertEquals($message->customdata, $savedmessage->customdata);
$this->assertContains('datakey', $savedmessage->customdata);
// Check it was a unserialisable json.
$customdata = json_decode($savedmessage->customdata);
$this->assertEquals('data', $customdata->datakey);
$this->assertEquals(1, $customdata->courseid);
$this->assertTimeCurrent($savedmessage->timecreated);
$record = $DB->get_record('messages', array('id' => $savedmessage->id), '*', MUST_EXIST);
unset($savedmessage->useridto);

View File

@ -3116,7 +3116,12 @@ class core_message_external extends external_api {
'timecreated' => new external_value(PARAM_INT, 'Time created'),
'timeread' => new external_value(PARAM_INT, 'Time read'),
'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name')
'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name'),
'component' => new external_value(PARAM_TEXT, 'The component that generated the notification',
VALUE_OPTIONAL),
'eventtype' => new external_value(PARAM_TEXT, 'The type of notification', VALUE_OPTIONAL),
'customdata' => new external_value(PARAM_RAW, 'Custom data to be passed to the message processor.
The data here is serialised using json_encode().', VALUE_OPTIONAL),
), 'message'
)
),

View File

@ -72,7 +72,7 @@ class api {
n.subject, n.fullmessage, n.fullmessageformat,
n.fullmessagehtml, n.smallmessage, n.contexturl,
n.contexturlname, n.timecreated, n.component,
n.eventtype, n.timeread
n.eventtype, n.timeread, n.customdata
FROM {notifications} n
WHERE n.id IN (SELECT notificationid FROM {message_popup_notifications})
AND n.useridto = ?

View File

@ -165,6 +165,8 @@ class message_popup_external extends external_api {
'component' => new external_value(PARAM_TEXT, 'The component that generated the notification',
VALUE_OPTIONAL),
'eventtype' => new external_value(PARAM_TEXT, 'The type of notification', VALUE_OPTIONAL),
'customdata' => new external_value(PARAM_RAW, 'Custom data to be passed to the message processor.
The data here is serialised using json_encode().', VALUE_OPTIONAL),
), 'message'
)
),

View File

@ -49,6 +49,7 @@ trait message_popup_test_helper {
$record->fullmessage = $message;
$record->smallmessage = $message;
$record->timecreated = $timecreated ? $timecreated : time();
$record->customdata = json_encode(['datakey' => 'data']);
$id = $DB->insert_record('notifications', $record);

View File

@ -96,6 +96,8 @@ class message_popup_externallib_testcase extends advanced_testcase {
$this->setAdminUser();
$result = message_popup_external::get_popup_notifications($recipient->id, false, 0, 0);
$this->assertCount(4, $result['notifications']);
// Check we receive custom data as a unserialisable json.
$this->assertObjectHasAttribute('datakey', json_decode($result['notifications'][0]->customdata));
$this->setUser($recipient);
$result = message_popup_external::get_popup_notifications($recipient->id, false, 0, 0);

View File

@ -1612,6 +1612,7 @@ class core_message_externallib_testcase extends externallib_advanced_testcase {
$eventdata->fullmessageformat = FORMAT_PLAIN;
$eventdata->fullmessagehtml = '<strong>Feedback submitted</strong>';
$eventdata->smallmessage = '';
$eventdata->customdata = ['datakey' => 'data'];
message_send($eventdata);
$this->setUser($user1);
@ -1644,6 +1645,10 @@ class core_message_externallib_testcase extends externallib_advanced_testcase {
$messages = core_message_external::get_messages(0, $user1->id, 'notifications', true, true, 0, 0);
$messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
$this->assertCount(1, $messages['messages']);
// Check we receive custom data as a unserialisable json.
$this->assertObjectHasAttribute('datakey', json_decode($messages['messages'][0]['customdata']));
$this->assertEquals('mod_feedback', $messages['messages'][0]['component']);
$this->assertEquals('submission', $messages['messages'][0]['eventtype']);
// Test warnings.
$CFG->messaging = 0;

View File

@ -9,6 +9,13 @@ information provided here is intended especially for developers.
functionality and remove all the legacy code (see MDL-63915).
Note - It's still possible to view another user's messages if you have the right capabilities and are able to
'log-in as' them.
* A new 'customdata' field for both messages and notifications has been added. This new field can store any custom data
serialised using json_encode().
This new field can be used for storing any data not fitting in the current message structure. For example, it will be used
to store additional information for the "Mobile notifications" processor.
Existing external functions: core_message_get_messages and message_popup_get_popup_notifications has been udated to return the
new field.
* External function core_message_get_messages now returns the component and eventtype.
=== 3.6 ===

View File

@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die();
$version = 2019041800.00; // YYYYMMDD = weekly release date of this DEV branch.
$version = 2019041800.01; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.