Beispiel #1
0
 /**
  * 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;
 }
Beispiel #2
0
/**
 * 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')) . '&nbsp;&nbsp;&nbsp;' . 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();
    }
}
Beispiel #3
0
/**
 * 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;
}
Beispiel #4
0
/**
 * 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;
}
Beispiel #5
0
/**
* 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);
    }
}
Beispiel #7
0
 /**
  * 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;
 }
Beispiel #8
0
/**
 * 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;
}
Beispiel #9
0
/**
 * 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;
}
Beispiel #10
0
 /**
  * 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());
 }
Beispiel #11
0
 /**
  * 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);
 }
Beispiel #12
0
 /**
  * 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();
 }