/** * Mark a single message as read, trigger message_viewed event * * @param int $messageid id of the message (in the message table) * @param int $timeread timestamp for when the message should be marked read * @return external_description * @throws invalid_parameter_exception * @throws moodle_exception * @since 2.9 */ public static function mark_message_read($messageid, $timeread) { global $CFG, $DB, $USER; // Check if private messaging between users is allowed. if (empty($CFG->messaging)) { throw new moodle_exception('disabled', 'message'); } // Warnings array, it can be empty at the end but is mandatory. $warnings = array(); // Validate params. $params = array('messageid' => $messageid, 'timeread' => $timeread); $params = self::validate_parameters(self::mark_message_read_parameters(), $params); // Validate context. $context = context_system::instance(); self::validate_context($context); $message = $DB->get_record('message', array('id' => $params['messageid']), '*', MUST_EXIST); if ($message->useridto != $USER->id) { throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read'); } $messageid = message_mark_message_read($message, $params['timeread']); $results = array('messageid' => $messageid, 'warnings' => $warnings); return $results; }
/** * If new messages are waiting for the current user, then insert * JavaScript to pop up the messaging window into the page * * @return void */ function message_popup_window() { global $USER, $DB, $PAGE, $CFG; if (!$PAGE->get_popup_notification_allowed() || empty($CFG->messaging)) { return; } if (!isloggedin() || isguestuser()) { return; } if (!isset($USER->message_lastpopup)) { $USER->message_lastpopup = 0; } else { if ($USER->message_lastpopup > time() - 120) { // Don't run the query to check whether to display a popup if its been run in the last 2 minutes. return; } } // A quick query to check whether the user has new messages. $messagecount = $DB->count_records('message', array('useridto' => $USER->id)); if ($messagecount < 1) { return; } // There are unread messages so now do a more complex but slower query. $messagesql = "SELECT m.id, c.blocked\n FROM {message} m\n JOIN {message_working} mw ON m.id=mw.unreadmessageid\n JOIN {message_processors} p ON mw.processorid=p.id\n JOIN {user} u ON m.useridfrom=u.id\n LEFT JOIN {message_contacts} c ON c.contactid = m.useridfrom\n AND c.userid = m.useridto\n WHERE m.useridto = :userid\n AND p.name='popup'"; // If the user was last notified over an hour ago we can re-notify them of old messages // so don't worry about when the new message was sent. $lastnotifiedlongago = $USER->message_lastpopup < time() - 3600; if (!$lastnotifiedlongago) { $messagesql .= 'AND m.timecreated > :lastpopuptime'; } $waitingmessages = $DB->get_records_sql($messagesql, array('userid' => $USER->id, 'lastpopuptime' => $USER->message_lastpopup)); $validmessages = 0; foreach ($waitingmessages as $messageinfo) { if ($messageinfo->blocked) { // Message is from a user who has since been blocked so just mark it read. // Get the full message to mark as read. $messageobject = $DB->get_record('message', array('id' => $messageinfo->id)); message_mark_message_read($messageobject, time()); } else { $validmessages++; } } if ($validmessages > 0) { $strmessages = get_string('unreadnewmessages', 'message', $validmessages); $strgomessage = get_string('gotomessages', 'message'); $strstaymessage = get_string('ignore', 'admin'); $notificationsound = null; $beep = get_user_preferences('message_beepnewmessage', ''); if (!empty($beep)) { // Browsers will work down this list until they find something they support. $sourcetags = html_writer::empty_tag('source', array('src' => $CFG->wwwroot . '/message/bell.wav', 'type' => 'audio/wav')); $sourcetags .= html_writer::empty_tag('source', array('src' => $CFG->wwwroot . '/message/bell.ogg', 'type' => 'audio/ogg')); $sourcetags .= html_writer::empty_tag('source', array('src' => $CFG->wwwroot . '/message/bell.mp3', 'type' => 'audio/mpeg')); $sourcetags .= html_writer::empty_tag('embed', array('src' => $CFG->wwwroot . '/message/bell.wav', 'autostart' => 'true', 'hidden' => 'true')); $notificationsound = html_writer::tag('audio', $sourcetags, array('preload' => 'auto', 'autoplay' => 'autoplay')); } $url = $CFG->wwwroot . '/message/index.php'; $content = html_writer::start_tag('div', array('id' => 'newmessageoverlay', 'class' => 'mdl-align')) . html_writer::start_tag('div', array('id' => 'newmessagetext')) . $strmessages . html_writer::end_tag('div') . $notificationsound . html_writer::start_tag('div', array('id' => 'newmessagelinks')) . html_writer::link($url, $strgomessage, array('id' => 'notificationyes')) . ' ' . html_writer::link('', $strstaymessage, array('id' => 'notificationno')) . html_writer::end_tag('div'); html_writer::end_tag('div'); $PAGE->requires->js_init_call('M.core_message.init_notification', array('', $content, $url)); $USER->message_lastpopup = time(); } }
/** * Called when a message provider wants to send a message. * This functions checks the message recipient's message processor configuration then * sends the message to the configured processors * * Required parameters of the $eventdata object: * component string component name. must exist in message_providers * name string message type name. must exist in message_providers * userfrom object|int the user sending the message * userto object|int the message recipient * subject string the message subject * fullmessage string the full message in a given format * fullmessageformat int the format if the full message (FORMAT_MOODLE, FORMAT_HTML, ..) * fullmessagehtml string the full version (the message processor will choose with one to use) * smallmessage string the small version of the message * * Optional parameters of the $eventdata object: * notification bool should the message be considered as a notification rather than a personal message * contexturl string if this is a notification then you can specify a url to view the event. For example the forum post the user is being notified of. * contexturlname string the display text for contexturl * * @category message * @param object $eventdata information about the message (component, userfrom, userto, ...) * @return mixed the integer ID of the new message or false if there was a problem with a processor */ function message_send($eventdata) { global $CFG, $DB; //new message ID to return $messageid = false; //TODO: we need to solve problems with database transactions here somehow, for now we just prevent transactions - sorry $DB->transactions_forbidden(); if (is_number($eventdata->userto)) { $eventdata->userto = $DB->get_record('user', array('id' => $eventdata->userto)); } if (is_int($eventdata->userfrom)) { $eventdata->userfrom = $DB->get_record('user', array('id' => $eventdata->userfrom)); } if (!isset($eventdata->userto->auth) or !isset($eventdata->userto->suspended) or !isset($eventdata->userto->deleted)) { $eventdata->userto = $DB->get_record('user', array('id' => $eventdata->userto->id)); } //after how long inactive should the user be considered logged off? if (isset($CFG->block_online_users_timetosee)) { $timetoshowusers = $CFG->block_online_users_timetosee * 60; } else { $timetoshowusers = 300;//5 minutes } // Work out if the user is logged in or not if (!empty($eventdata->userto->lastaccess) && (time()-$timetoshowusers) < $eventdata->userto->lastaccess) { $userstate = 'loggedin'; } else { $userstate = 'loggedoff'; } // Create the message object $savemessage = new stdClass(); $savemessage->useridfrom = $eventdata->userfrom->id; $savemessage->useridto = $eventdata->userto->id; $savemessage->subject = $eventdata->subject; $savemessage->fullmessage = $eventdata->fullmessage; $savemessage->fullmessageformat = $eventdata->fullmessageformat; $savemessage->fullmessagehtml = $eventdata->fullmessagehtml; $savemessage->smallmessage = $eventdata->smallmessage; if (!empty($eventdata->notification)) { $savemessage->notification = $eventdata->notification; } else { $savemessage->notification = 0; } if (!empty($eventdata->contexturl)) { $savemessage->contexturl = $eventdata->contexturl; } else { $savemessage->contexturl = null; } if (!empty($eventdata->contexturlname)) { $savemessage->contexturlname = $eventdata->contexturlname; } else { $savemessage->contexturlname = null; } $savemessage->timecreated = time(); if (PHPUNIT_TEST and class_exists('phpunit_util')) { // Add some more tests to make sure the normal code can actually work. $componentdir = get_component_directory($eventdata->component); if (!$componentdir or !is_dir($componentdir)) { throw new coding_exception('Invalid component specified in message-send(): '.$eventdata->component); } if (!file_exists("$componentdir/db/messages.php")) { throw new coding_exception("$eventdata->component does not contain db/messages.php necessary for message_send()"); } $messageproviders = null; include("$componentdir/db/messages.php"); if (!isset($messageproviders[$eventdata->name])) { throw new coding_exception("Missing messaging defaults for event '$eventdata->name' in '$eventdata->component' messages.php file"); } unset($componentdir); unset($messageproviders); // Now ask phpunit if it wants to catch this message. if (phpunit_util::is_redirecting_messages()) { $savemessage->timeread = time(); $messageid = $DB->insert_record('message_read', $savemessage); $message = $DB->get_record('message_read', array('id'=>$messageid)); phpunit_util::message_sent($message); return $messageid; } } // Fetch enabled processors $processors = get_message_processors(true); // Fetch default (site) preferences $defaultpreferences = get_message_output_default_preferences(); // Preset variables $processorlist = array(); $preferencebase = $eventdata->component.'_'.$eventdata->name; // Fill in the array of processors to be used based on default and user preferences foreach ($processors as $processor) { // First find out permissions $defaultpreference = $processor->name.'_provider_'.$preferencebase.'_permitted'; if (isset($defaultpreferences->{$defaultpreference})) { $permitted = $defaultpreferences->{$defaultpreference}; } else { //MDL-25114 They supplied an $eventdata->component $eventdata->name combination which doesn't //exist in the message_provider table (thus there is no default settings for them) $preferrormsg = get_string('couldnotfindpreference', 'message', $defaultpreference); throw new coding_exception($preferrormsg,'blah'); } // Find out if user has configured this output // Some processors cannot function without settings from the user $userisconfigured = $processor->object->is_user_configured($eventdata->userto); // DEBUG: notify if we are forcing unconfigured output if ($permitted == 'forced' && !$userisconfigured) { debugging('Attempt to force message delivery to user who has "'.$processor->name.'" output unconfigured', DEBUG_NORMAL); } // Warn developers that necessary data is missing regardless of how the processors are configured if (!isset($eventdata->userto->emailstop)) { debugging('userto->emailstop is not set. Retrieving it from the user table'); $eventdata->userto->emailstop = $DB->get_field('user', 'emailstop', array('id'=>$eventdata->userto->id)); } // Populate the list of processors we will be using if ($permitted == 'forced' && $userisconfigured) { // An admin is forcing users to use this message processor. Use this processor unconditionally. $processorlist[] = $processor->name; } else if ($permitted == 'permitted' && $userisconfigured && !$eventdata->userto->emailstop) { // User has not disabled notifications // See if user set any notification preferences, otherwise use site default ones $userpreferencename = 'message_provider_'.$preferencebase.'_'.$userstate; if ($userpreference = get_user_preferences($userpreferencename, null, $eventdata->userto->id)) { if (in_array($processor->name, explode(',', $userpreference))) { $processorlist[] = $processor->name; } } else if (isset($defaultpreferences->{$userpreferencename})) { if (in_array($processor->name, explode(',', $defaultpreferences->{$userpreferencename}))) { $processorlist[] = $processor->name; } } } } if (empty($processorlist) && $savemessage->notification) { //if they have deselected all processors and its a notification mark it read. The user doesnt want to be bothered $savemessage->timeread = time(); $messageid = $DB->insert_record('message_read', $savemessage); } else { // Process the message // Store unread message just in case we can not send it $messageid = $savemessage->id = $DB->insert_record('message', $savemessage); $eventdata->savedmessageid = $savemessage->id; // Try to deliver the message to each processor if (!empty($processorlist)) { foreach ($processorlist as $procname) { if (!$processors[$procname]->object->send_message($eventdata)) { debugging('Error calling message processor '.$procname); $messageid = false; } } //if messaging is disabled and they previously had forum notifications handled by the popup processor //or any processor that puts a row in message_working then the notification will remain forever //unread. To prevent this mark the message read if messaging is disabled if (empty($CFG->messaging)) { require_once($CFG->dirroot.'/message/lib.php'); $messageid = message_mark_message_read($savemessage, time()); } else if ( $DB->count_records('message_working', array('unreadmessageid' => $savemessage->id)) == 0){ //if there is no more processors that want to process this we can move message to message_read require_once($CFG->dirroot.'/message/lib.php'); $messageid = message_mark_message_read($savemessage, time(), true); } } } return $messageid; }
/** * Moves messages from a particular user from the message table (unread messages) to message_read * This is typically only used when a user is deleted * * @param object $userid User id * @return boolean success */ function message_move_userfrom_unread2read($userid) { global $DB; // move all unread messages from message table to message_read if ($messages = $DB->get_records_select('message', 'useridfrom = ?', array($userid), 'timecreated')) { foreach ($messages as $message) { message_mark_message_read($message, 0); //set timeread to 0 as the message was never read } } return true; }
/** * marks ALL messages being sent from $fromuserid to $touserid as read * @param int $touserid the id of the message recipient * @param int $fromuserid the id of the message sender * @return void */ function message_mark_messages_read($touserid, $fromuserid){ global $DB; $sql = 'SELECT m.* FROM {message} m WHERE m.useridto=:useridto AND m.useridfrom=:useridfrom'; $messages = $DB->get_recordset_sql($sql, array('useridto' => $touserid,'useridfrom' => $fromuserid)); foreach ($messages as $message) { message_mark_message_read($message, time()); } }
/** * Mark a single message as read * @param message an object with an object property ie $message->id which is an id in the message table * @param int $timeread the timestamp for when the message should be marked read. Usually time(). * @param bool $messageworkingempty Is the message_working table already confirmed empty for this message? * @return void */ function tm_message_mark_message_read($message, $timeread, $messageworkingempty=false) { global $DB; $message->timeread = $timeread; $messageid = $message->id; $messagereadid = message_mark_message_read($message, $timeread, $messageworkingempty); // modify the metadata record to point to the read message instead $metadataid = $DB->get_field('message_metadata', 'id', array('messageid' => $messageid)); if ($metadataid) { $todb = new stdClass(); $todb->id = $metadataid; $todb->messageid = null; // remove message id $todb->messagereadid = $messagereadid; // add the read id $DB->update_record('message_metadata', $todb); } }
/** * Send message to message processors. * * @param \stdClass|\core\message\message $eventdata * @param \stdClass $savemessage * @param array $processorlist * @return int $messageid */ protected static function send_message_to_processors($eventdata, \stdClass $savemessage, array $processorlist) { global $CFG, $DB; // We cannot communicate with external systems in DB transactions, // buffer the messages if necessary. if ($DB->is_transaction_started()) { // We need to clone all objects so that devs may not modify it from outside later. $eventdata = clone $eventdata; $eventdata->userto = clone $eventdata->userto; $eventdata->userfrom = clone $eventdata->userfrom; // Conserve some memory the same was as $USER setup does. unset($eventdata->userto->description); unset($eventdata->userfrom->description); self::$buffer[] = array($eventdata, $savemessage, $processorlist); return $savemessage->id; } $processors = get_message_processors(true); $failed = false; foreach ($processorlist as $procname) { // Let new messaging class add custom content based on the processor. $proceventdata = $eventdata instanceof message ? $eventdata->get_eventobject_for_processor($procname) : $eventdata; if (!$processors[$procname]->object->send_message($proceventdata)) { debugging('Error calling message processor ' . $procname); $failed = true; // Previously the $messageid = false here was overridden // by other processors and message_mark_message_read() below. } } // Trigger event for sending a message - must be done before marking as read. \core\event\message_sent::create_from_ids($eventdata->userfrom->id, $eventdata->userto->id, $savemessage->id)->trigger(); if (empty($CFG->messaging)) { // If messaging is disabled and they previously had forum notifications handled by the popup processor // or any processor that puts a row in message_working then the notification will remain forever // unread. To prevent this mark the message read if messaging is disabled. $messageid = message_mark_message_read($savemessage, time()); } else { if ($failed) { // Something failed, better keep it as unread then. $messageid = $savemessage->id; } else { if ($DB->count_records('message_working', array('unreadmessageid' => $savemessage->id)) == 0) { // If there is no more processors that want to process this we can move message to message_read. $messageid = message_mark_message_read($savemessage, time(), true); } else { // Some processor is still working on the data, let's keep it unread. $messageid = $savemessage->id; } } } return $messageid; }
/** * Called when a message provider wants to send a message. * This functions checks the user's processor configuration to send the given type of message, * then tries to send it. * * Required parameter $eventdata structure: * component string component name. must exist in message_providers * name string message type name. must exist in message_providers * userfrom object|int the user sending the message * userto object|int the message recipient * subject string the message subject * fullmessage - the full message in a given format * fullmessageformat - the format if the full message (FORMAT_MOODLE, FORMAT_HTML, ..) * fullmessagehtml - the full version (the message processor will choose with one to use) * smallmessage - the small version of the message * contexturl - if this is a notification then you can specify a url to view the event. For example the forum post the user is being notified of. * contexturlname - the display text for contexturl * * @param object $eventdata information about the message (component, userfrom, userto, ...) * @return int|false the ID of the new message or false if there was a problem with a processor */ function message_send($eventdata) { global $CFG, $DB; //new message ID to return $messageid = false; //TODO: we need to solve problems with database transactions here somehow, for now we just prevent transactions - sorry $DB->transactions_forbidden(); if (is_int($eventdata->userto)) { $eventdata->userto = $DB->get_record('user', array('id' => $eventdata->userto)); } if (is_int($eventdata->userfrom)) { $eventdata->userfrom = $DB->get_record('user', array('id' => $eventdata->userfrom)); } //after how long inactive should the user be considered logged off? if (isset($CFG->block_online_users_timetosee)) { $timetoshowusers = $CFG->block_online_users_timetosee * 60; } else { $timetoshowusers = 300;//5 minutes } // Work out if the user is logged in or not if (!empty($eventdata->userto->lastaccess) && (time()-$timetoshowusers) < $eventdata->userto->lastaccess) { $userstate = 'loggedin'; } else { $userstate = 'loggedoff'; } // Create the message object $savemessage = new stdClass(); $savemessage->useridfrom = $eventdata->userfrom->id; $savemessage->useridto = $eventdata->userto->id; $savemessage->subject = $eventdata->subject; $savemessage->fullmessage = $eventdata->fullmessage; $savemessage->fullmessageformat = $eventdata->fullmessageformat; $savemessage->fullmessagehtml = $eventdata->fullmessagehtml; $savemessage->smallmessage = $eventdata->smallmessage; if (!empty($eventdata->notification)) { $savemessage->notification = $eventdata->notification; } else { $savemessage->notification = 0; } if (!empty($eventdata->contexturl)) { $savemessage->contexturl = $eventdata->contexturl; } else { $savemessage->contexturl = null; } if (!empty($eventdata->contexturlname)) { $savemessage->contexturlname = $eventdata->contexturlname; } else { $savemessage->contexturlname = null; } $savemessage->timecreated = time(); // Fetch enabled processors $processors = get_message_processors(true); // Fetch default (site) preferences $defaultpreferences = get_message_output_default_preferences(); // Preset variables $processorlist = array(); $preferencebase = $eventdata->component.'_'.$eventdata->name; // Fill in the array of processors to be used based on default and user preferences foreach ($processors as $processor) { // First find out permissions $defaultpreference = $processor->name.'_provider_'.$preferencebase.'_permitted'; if (isset($defaultpreferences->{$defaultpreference})) { $permitted = $defaultpreferences->{$defaultpreference}; } else { //MDL-25114 They supplied an $eventdata->component $eventdata->name combination which doesn't //exist in the message_provider table (thus there is no default settings for them) $preferrormsg = get_string('couldnotfindpreference', 'message', $preferencename); throw new coding_exception($preferrormsg,'blah'); } // Find out if user has configured this output $userisconfigured = $processor->object->is_user_configured($eventdata->userto); // DEBUG: noify if we are forcing unconfigured output if ($permitted == 'forced' && !$userisconfigured) { debugging('Attempt to force message delivery to user who has "'.$processor->name.'" output unconfigured', DEBUG_NORMAL); } // Populate the list of processors we will be using if ($permitted == 'forced' && $userisconfigured) { // We force messages for this processor, so use this processor unconditionally if user has configured it $processorlist[] = $processor->name; } else if ($permitted == 'permitted' && $userisconfigured) { // User settings are permitted, see if user set any, otherwise use site default ones $userpreferencename = 'message_provider_'.$preferencebase.'_'.$userstate; if ($userpreference = get_user_preferences($userpreferencename, null, $eventdata->userto->id)) { if (in_array($processor->name, explode(',', $userpreference))) { $processorlist[] = $processor->name; } } else if (isset($defaultpreferences->{$userpreferencename})) { if (in_array($processor->name, explode(',', $defaultpreferences->{$userpreferencename}))) { $processorlist[] = $processor->name; } } } } if (empty($processorlist) && $savemessage->notification) { //if they have deselected all processors and its a notification mark it read. The user doesnt want to be bothered $savemessage->timeread = time(); $messageid = $DB->insert_record('message_read', $savemessage); } else { // Process the message // Store unread message just in case we can not send it $messageid = $savemessage->id = $DB->insert_record('message', $savemessage); $eventdata->savedmessageid = $savemessage->id; // Try to deliver the message to each processor if (!empty($processorlist)) { foreach ($processorlist as $procname) { if (!$processors[$procname]->object->send_message($eventdata)) { debugging('Error calling message processor '.$procname); $messageid = false; } } //if messaging is disabled and they previously had forum notifications handled by the popup processor //or any processor that puts a row in message_working then the notification will remain forever //unread. To prevent this mark the message read if messaging is disabled if (empty($CFG->messaging)) { require_once($CFG->dirroot.'/message/lib.php'); $messageid = message_mark_message_read($savemessage, time()); } else if ( $DB->count_records('message_working', array('unreadmessageid' => $savemessage->id)) == 0){ //if there is no more processors that want to process this we can move message to message_read require_once($CFG->dirroot.'/message/lib.php'); $messageid = message_mark_message_read($savemessage, time(), true); } } } return $messageid; }
/** * Called when a message provider wants to send a message. * This functions checks the user's processor configuration to send the given type of message, * then tries to send it. * * Required parameter $eventdata structure: * component string component name. must exist in message_providers * name string message type name. must exist in message_providers * userfrom object the user sending the message * userto object the message recipient * subject string the message subject * fullmessage - the full message in a given format * fullmessageformat - the format if the full message (FORMAT_MOODLE, FORMAT_HTML, ..) * fullmessagehtml - the full version (the message processor will choose with one to use) * smallmessage - the small version of the message * contexturl - if this is a notification then you can specify a url to view the event. For example the forum post the user is being notified of. * contexturlname - the display text for contexturl * * @param object $eventdata information about the message (component, userfrom, userto, ...) * @return int|false the ID of the new message or false if there was a problem with a processor */ function message_send($eventdata) { global $CFG, $DB; //new message ID to return $messageid = false; //TODO: we need to solve problems with database transactions here somehow, for now we just prevent transactions - sorry $DB->transactions_forbidden(); if (is_int($eventdata->userto)) { mtrace('message_send() userto is a user ID when it should be a user object'); $eventdata->userto = $DB->get_record('user', array('id' => $eventdata->useridto)); } if (is_int($eventdata->userfrom)) { mtrace('message_send() userfrom is a user ID when it should be a user object'); $eventdata->userfrom = $DB->get_record('user', array('id' => $message->userfrom)); } //after how long inactive should the user be considered logged off? if (isset($CFG->block_online_users_timetosee)) { $timetoshowusers = $CFG->block_online_users_timetosee * 60; } else { $timetoshowusers = 300;//5 minutes } // Work out if the user is logged in or not if (!empty($eventdata->userto->lastaccess) && (time()-$timetoshowusers) < $eventdata->userto->lastaccess) { $userstate = 'loggedin'; } else { $userstate = 'loggedoff'; } // Create the message object $savemessage = new stdClass(); $savemessage->useridfrom = $eventdata->userfrom->id; $savemessage->useridto = $eventdata->userto->id; $savemessage->subject = $eventdata->subject; $savemessage->fullmessage = $eventdata->fullmessage; $savemessage->fullmessageformat = $eventdata->fullmessageformat; $savemessage->fullmessagehtml = $eventdata->fullmessagehtml; $savemessage->smallmessage = $eventdata->smallmessage; if (!empty($eventdata->notification)) { $savemessage->notification = $eventdata->notification; } else { $savemessage->notification = 0; } if (!empty($eventdata->contexturl)) { $savemessage->contexturl = $eventdata->contexturl; } else { $savemessage->contexturl = null; } if (!empty($eventdata->contexturlname)) { $savemessage->contexturlname = $eventdata->contexturlname; } else { $savemessage->contexturlname = null; } $savemessage->timecreated = time(); // Find out what processors are defined currently // When a user doesn't have settings none gets return, if he doesn't want contact "" gets returned $preferencename = 'message_provider_'.$eventdata->component.'_'.$eventdata->name.'_'.$userstate; $processor = get_user_preferences($preferencename, null, $eventdata->userto->id); if ($processor == NULL) { //this user never had a preference, save default if (!message_set_default_message_preferences($eventdata->userto)) { print_error('cannotsavemessageprefs', 'message'); } $processor = get_user_preferences($preferencename, NULL, $eventdata->userto->id); if (empty($processor)) { //MDL-25114 They supplied an $eventdata->component $eventdata->name combination which doesn't //exist in the message_provider table $preferrormsg = get_string('couldnotfindpreference', 'message', $preferencename); throw new coding_exception($preferrormsg,'blah'); } } if ($processor=='none' && $savemessage->notification) { //if they have deselected all processors and its a notification mark it read. The user doesnt want to be bothered $savemessage->timeread = time(); $messageid = $DB->insert_record('message_read', $savemessage); } else { // Process the message // Store unread message just in case we can not send it $messageid = $savemessage->id = $DB->insert_record('message', $savemessage); $eventdata->savedmessageid = $savemessage->id; // Try to deliver the message to each processor if ($processor!='none') { $processorlist = explode(',', $processor); foreach ($processorlist as $procname) { $processorfile = $CFG->dirroot. '/message/output/'.$procname.'/message_output_'.$procname.'.php'; if (is_readable($processorfile)) { include_once($processorfile); // defines $module with version etc $processclass = 'message_output_' . $procname; if (class_exists($processclass)) { $pclass = new $processclass(); if (!$pclass->send_message($eventdata)) { debugging('Error calling message processor '.$procname); $messageid = false; } } } else { debugging('Error finding message processor '.$procname); $messageid = false; } } //if messaging is disabled and they previously had forum notifications handled by the popup processor //or any processor that puts a row in message_working then the notification will remain forever //unread. To prevent this mark the message read if messaging is disabled if (empty($CFG->messaging)) { require_once($CFG->dirroot.'/message/lib.php'); $messageid = message_mark_message_read($savemessage, time()); } else if ( $DB->count_records('message_working', array('unreadmessageid' => $savemessage->id)) == 0){ //if there is no more processors that want to process this we can move message to message_read require_once($CFG->dirroot.'/message/lib.php'); $messageid = message_mark_message_read($savemessage, time(), true); } } } return $messageid; }
/** * Test the message viewed event. */ public function test_message_viewed() { global $DB; // Create a message to mark as read. $message = new stdClass(); $message->useridfrom = '1'; $message->useridto = '2'; $message->subject = 'Subject'; $message->message = 'Message'; $message->id = $DB->insert_record('message', $message); // Trigger and capture the event. $sink = $this->redirectEvents(); message_mark_message_read($message, time()); $events = $sink->get_events(); $event = reset($events); // Check that the event data is valid. $this->assertInstanceOf('\\core\\event\\message_viewed', $event); $this->assertEquals(context_user::instance(2), $event->get_context()); $url = new moodle_url('/message/index.php', array('user1' => $event->userid, 'user2' => $event->relateduserid)); $this->assertEquals($url, $event->get_url()); }
/** * Test delete_message. */ public function test_delete_message() { global $DB; $this->resetAfterTest(true); $user1 = self::getDataGenerator()->create_user(); $user2 = self::getDataGenerator()->create_user(); $user3 = self::getDataGenerator()->create_user(); $user4 = self::getDataGenerator()->create_user(); // Login as user1. $this->setUser($user1); $this->assertEquals(array(), core_message_external::create_contacts(array($user2->id, $user3->id))); // User user1 does not interchange messages with user3. $m1to2 = message_post_message($user1, $user2, 'some random text 1', FORMAT_MOODLE); $m2to3 = message_post_message($user2, $user3, 'some random text 3', FORMAT_MOODLE); $m3to2 = message_post_message($user3, $user2, 'some random text 4', FORMAT_MOODLE); $m3to4 = message_post_message($user3, $user4, 'some random text 4', FORMAT_MOODLE); // Retrieve all messages sent by user2 (they are currently unread). $lastmessages = message_get_messages($user1->id, $user2->id, 0, false); // Delete a message not read, as a user from. $result = core_message_external::delete_message($m1to2, $user1->id, false); $result = external_api::clean_returnvalue(core_message_external::delete_message_returns(), $result); $this->assertTrue($result['status']); $this->assertCount(0, $result['warnings']); $deletedmessage = $DB->get_record('message', array('id' => $m1to2)); $this->assertNotEquals(0, $deletedmessage->timeuserfromdeleted); // Try to delete the same message again. $result = core_message_external::delete_message($m1to2, $user1->id, false); $result = external_api::clean_returnvalue(core_message_external::delete_message_returns(), $result); $this->assertFalse($result['status']); // Try to delete a message that does not belong to me. try { $messageid = core_message_external::delete_message($m2to3, $user3->id, false); $this->fail('Exception expected due invalid messageid.'); } catch (moodle_exception $e) { $this->assertEquals('You do not have permission to delete this message', $e->errorcode); } $this->setUser($user3); // Delete a message not read, as a user to. $result = core_message_external::delete_message($m2to3, $user3->id, false); $result = external_api::clean_returnvalue(core_message_external::delete_message_returns(), $result); $this->assertTrue($result['status']); $this->assertCount(0, $result['warnings']); $deletedmessage = $DB->get_record('message', array('id' => $m2to3)); $this->assertNotEquals(0, $deletedmessage->timeusertodeleted); // Delete a message read. $message = $DB->get_record('message', array('id' => $m3to2)); $messageid = message_mark_message_read($message, time()); $result = core_message_external::delete_message($messageid, $user3->id); $result = external_api::clean_returnvalue(core_message_external::delete_message_returns(), $result); $this->assertTrue($result['status']); $this->assertCount(0, $result['warnings']); $deletedmessage = $DB->get_record('message_read', array('id' => $messageid)); $this->assertNotEquals(0, $deletedmessage->timeuserfromdeleted); // Invalid message ids. try { $result = core_message_external::delete_message(-1, $user1->id); $this->fail('Exception expected due invalid messageid.'); } catch (dml_missing_record_exception $e) { $this->assertEquals('invalidrecord', $e->errorcode); } // Invalid user. try { $result = core_message_external::delete_message($m1to2, -1, false); $this->fail('Exception expected due invalid user.'); } catch (moodle_exception $e) { $this->assertEquals('invaliduser', $e->errorcode); } // Not active user. delete_user($user2); try { $result = core_message_external::delete_message($m1to2, $user2->id, false); $this->fail('Exception expected due invalid user.'); } catch (moodle_exception $e) { $this->assertEquals('userdeleted', $e->errorcode); } // Now, as an admin, try to delete any message. $this->setAdminUser(); $result = core_message_external::delete_message($m3to4, $user4->id, false); $result = external_api::clean_returnvalue(core_message_external::delete_message_returns(), $result); $this->assertTrue($result['status']); $this->assertCount(0, $result['warnings']); $deletedmessage = $DB->get_record('message', array('id' => $m3to4)); $this->assertNotEquals(0, $deletedmessage->timeusertodeleted); }
/** * Marks ALL messages being sent from $fromuserid to $touserid as read. * * Can be filtered by type. * * @param int $touserid the id of the message recipient * @param int $fromuserid the id of the message sender * @param string $type filter the messages by type, either MESSAGE_TYPE_NOTIFICATION, MESSAGE_TYPE_MESSAGE or '' for all. * @return void */ public static function mark_all_read_for_user($touserid, $fromuserid = 0, $type = '') { global $DB; $params = array(); if (!empty($touserid)) { $params['useridto'] = $touserid; } if (!empty($fromuserid)) { $params['useridfrom'] = $fromuserid; } if (!empty($type)) { if (strtolower($type) == MESSAGE_TYPE_NOTIFICATION) { $params['notification'] = 1; } else { if (strtolower($type) == MESSAGE_TYPE_MESSAGE) { $params['notification'] = 0; } } } $messages = $DB->get_recordset('message', $params); foreach ($messages as $message) { message_mark_message_read($message, time()); } $messages->close(); }