mirror of
https://github.com/moodle/moodle.git
synced 2025-04-20 07:56:06 +02:00
MDL-63724 core_message: add send_message_to_conversation() to manager
This commit is contained in:
parent
aa083ab95f
commit
9581bc3c00
@ -186,6 +186,7 @@ $string['touserdoesntexist'] = 'You can not send a message to a user id ({$a}) t
|
||||
$string['unblockcontact'] = 'Unblock contact';
|
||||
$string['unknownuser'] = 'Unknown user';
|
||||
$string['unreadnotification'] = 'Unread notification: {$a}';
|
||||
$string['unreadnewgroupconversationmessage'] = 'New message from {$a->name} in {$a->conversationname}';
|
||||
$string['unreadnewmessage'] = 'New message from {$a}';
|
||||
$string['usercantbemessaged'] = 'You can\'t message {$a} due to their message preferences. Try adding them as a contact.';
|
||||
$string['viewfullnotification'] = 'View full notification';
|
||||
@ -201,4 +202,4 @@ $string['eventmessagecontactblocked'] = 'Message contact blocked';
|
||||
$string['eventmessagecontactunblocked'] = 'Message contact unblocked';
|
||||
$string['messagingdisabled'] = 'Messaging is disabled on this site, emails will be sent instead';
|
||||
$string['userisblockingyou'] = 'This user has blocked you from sending messages to them.';
|
||||
$string['userisblockingyounoncontact'] = '{$a} only accepts messages from their contacts.';
|
||||
$string['userisblockingyounoncontact'] = '{$a} only accepts messages from their contacts.';
|
||||
|
@ -45,6 +45,209 @@ class manager {
|
||||
/** @var array buffer of pending messages */
|
||||
protected static $buffer = array();
|
||||
|
||||
/**
|
||||
* Used for calling processors, and generating event data when sending a message to a conversation.
|
||||
*
|
||||
* This is ONLY used for messages of type 'message' (notification=0), and is responsible for:
|
||||
*
|
||||
* 1. generation of per-user event data (to pass to processors)
|
||||
* 2. generation of the processors for each recipient member of the conversation
|
||||
* 3. calling said processors for each member, passing in the per-user (local) eventdata.
|
||||
* 4. generation of an appropriate event for the message send, depending on the conversation type
|
||||
* - messages to individual conversations generate a 'message_sent' event (as per legacy send_message())
|
||||
* - messages to group conversations generate a 'group_message_sent' event.
|
||||
*
|
||||
* @param message $eventdata
|
||||
* @param \stdClass $savemessage
|
||||
* @return int
|
||||
*/
|
||||
public static function send_message_to_conversation(message $eventdata, \stdClass $savemessage) : int {
|
||||
global $DB, $CFG, $SITE;
|
||||
|
||||
if (empty($eventdata->convid)) {
|
||||
throw new \moodle_exception("Message is not being sent to a conversation. Please check event data.");
|
||||
}
|
||||
|
||||
// Fetch default (site) preferences.
|
||||
$defaultpreferences = get_message_output_default_preferences();
|
||||
$preferencebase = $eventdata->component.'_'.$eventdata->name;
|
||||
|
||||
// Because we're dealing with multiple recipients, we need to send a localised (per-user) version of the eventdata to each
|
||||
// processor, because of things like the language-specific subject. We're going to modify this, for each recipient member.
|
||||
// Any time we're modifying the event data here, we should be using the localised version.
|
||||
// This localised version is based on the generic event data, but we should keep that object intact, so we clone it.
|
||||
$localisedeventdata = clone $eventdata;
|
||||
|
||||
// Get user records for all members of the conversation.
|
||||
$sql = "SELECT u.*
|
||||
FROM {message_conversation_members} mcm
|
||||
JOIN {user} u
|
||||
ON (mcm.conversationid = :convid AND u.id = mcm.userid)
|
||||
ORDER BY id desc";
|
||||
$members = $DB->get_records_sql($sql, ['convid' => $eventdata->convid]);
|
||||
if (empty($members)) {
|
||||
throw new \moodle_exception("Conversation has no members or does not exist.");
|
||||
}
|
||||
|
||||
if (!is_object($localisedeventdata->userfrom)) {
|
||||
$localisedeventdata->userfrom = $members[$localisedeventdata->userfrom];
|
||||
}
|
||||
|
||||
// This should now hold only the other users (recipients).
|
||||
unset($members[$localisedeventdata->userfrom->id]);
|
||||
$otherusers = $members;
|
||||
|
||||
// Get conversation type and name. We'll use this to determine which message subject to generate, depending on type.
|
||||
$conv = $DB->get_record('message_conversations', ['id' => $eventdata->convid], 'id, type, name');
|
||||
|
||||
// We treat individual conversations the same as any direct message with 'userfrom' and 'userto' specified.
|
||||
// We know the other user, so set the 'userto' field so that the event code will get access to this field.
|
||||
// If this was a legacy caller (eventdata->userto is set), then use that instead, as we want to use the fields specified
|
||||
// in that object instead of using one fetched from the DB.
|
||||
$legacymessage = false;
|
||||
if ($conv->type == \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL) {
|
||||
if (isset($eventdata->userto)) {
|
||||
$legacymessage = true;
|
||||
} else {
|
||||
$otheruser = reset($otherusers);
|
||||
$eventdata->userto = $otheruser;
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch enabled processors.
|
||||
// If we are dealing with a message some processors may want to handle it regardless of user and site settings.
|
||||
$processors = array_filter(get_message_processors(false), function($processor) {
|
||||
if ($processor->object->force_process_messages()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return ($processor->enabled && $processor->configured);
|
||||
});
|
||||
|
||||
// For each member of the conversation, other than the sender:
|
||||
// 1. Set recipient specific event data (language specific, user prefs, etc)
|
||||
// 2. Generate recipient specific processor list
|
||||
// 3. Call send_message() to pass the message to processors and generate the relevant per-user events.
|
||||
$eventprocmaps = []; // Init the event/processors buffer.
|
||||
foreach ($otherusers as $recipient) {
|
||||
// If this message was a legacy (1:1) message, then we use the userto.
|
||||
if ($legacymessage) {
|
||||
$recipient = $eventdata->userto;
|
||||
}
|
||||
|
||||
$usertoisrealuser = (\core_user::is_real_user($recipient->id) != false);
|
||||
|
||||
// Using string manager directly so that strings in the message will be in the message recipients language rather than
|
||||
// the sender's.
|
||||
if ($conv->type == \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL) {
|
||||
$localisedeventdata->subject = get_string_manager()->get_string('unreadnewmessage', 'message',
|
||||
fullname($localisedeventdata->userfrom), $recipient->lang);
|
||||
} else if ($conv->type == \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP) {
|
||||
$stringdata = (object) ['name' => fullname($localisedeventdata->userfrom), 'conversationname' => $conv->name];
|
||||
$localisedeventdata->subject = get_string_manager()->get_string('unreadnewgroupconversationmessage', 'message',
|
||||
$stringdata, $recipient->lang);
|
||||
}
|
||||
|
||||
// Spoof the userto based on the current member id.
|
||||
$localisedeventdata->userto = $recipient;
|
||||
|
||||
$s = new \stdClass();
|
||||
$s->sitename = format_string($SITE->shortname, true, array('context' => \context_course::instance(SITEID)));
|
||||
// When the new interface lands, the URL may be reintroduced, but for now it isn't supported, so just hit the index.
|
||||
$s->url = $CFG->wwwroot.'/message/index.php';
|
||||
$emailtagline = get_string_manager()->get_string('emailtagline', 'message', $s, $recipient->lang);
|
||||
|
||||
$localisedeventdata->fullmessage = $eventdata->fullmessage;
|
||||
$localisedeventdata->fullmessagehtml = $eventdata->fullmessagehtml;
|
||||
if (!empty($localisedeventdata->fullmessage)) {
|
||||
$localisedeventdata->fullmessage .= "\n\n---------------------------------------------------------------------\n"
|
||||
. $emailtagline;
|
||||
}
|
||||
if (!empty($localisedeventdata->fullmessagehtml)) {
|
||||
$localisedeventdata->fullmessagehtml .=
|
||||
"<br><br>---------------------------------------------------------------------<br>" . $emailtagline;
|
||||
}
|
||||
|
||||
// If recipient is internal user (noreply user), and emailstop is set then don't send any msg.
|
||||
if (!$usertoisrealuser && !empty($recipient->emailstop)) {
|
||||
debugging('Attempt to send msg to internal (noreply) user', DEBUG_NORMAL);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the online state.
|
||||
if (isset($CFG->block_online_users_timetosee)) {
|
||||
$timetoshowusers = $CFG->block_online_users_timetosee * 60;
|
||||
} else {
|
||||
$timetoshowusers = 300;
|
||||
}
|
||||
|
||||
// Work out if the user is logged in or not.
|
||||
$userstate = 'loggedoff';
|
||||
if (!empty($localisedeventdata->userto->lastaccess)
|
||||
&& (time() - $timetoshowusers) < $localisedeventdata->userto->lastaccess) {
|
||||
$userstate = 'loggedin';
|
||||
}
|
||||
|
||||
// Fill in the array of processors to be used based on default and user preferences.
|
||||
$processorlist = [];
|
||||
foreach ($processors as $processor) {
|
||||
// Skip adding processors for internal user, if processor doesn't support sending message to internal user.
|
||||
if (!$usertoisrealuser && !$processor->object->can_send_to_any_users()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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 = "Could not load preference $defaultpreference. Make sure the component and name you supplied
|
||||
to message_send() are valid.";
|
||||
throw new coding_exception($preferrormsg);
|
||||
}
|
||||
|
||||
// Find out if user has configured this output.
|
||||
// Some processors cannot function without settings from the user.
|
||||
$userisconfigured = $processor->object->is_user_configured($recipient);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Populate the list of processors we will be using.
|
||||
if (!$eventdata->notification && $processor->object->force_process_messages()) {
|
||||
$processorlist[] = $processor->name;
|
||||
} else 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 && !$recipient->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, $recipient)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Send the localised eventdata to each processor for the current member.
|
||||
self::call_processors($localisedeventdata, $processorlist);
|
||||
}
|
||||
// Trigger the event using the original message eventdata as events don't need any of the localised information.
|
||||
self::trigger_message_events($eventdata, $savemessage);
|
||||
|
||||
return $savemessage->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the message sending.
|
||||
*
|
||||
@ -149,6 +352,7 @@ class manager {
|
||||
*/
|
||||
public static function database_transaction_rolledback() {
|
||||
self::$buffer = array();
|
||||
self::$convmessagebuffer = array();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -173,6 +377,7 @@ class manager {
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
protected static function trigger_message_events(message $eventdata, \stdClass $savemessage) {
|
||||
global $DB;
|
||||
if ($eventdata->notification) {
|
||||
\core\event\notification_sent::create_from_ids(
|
||||
$eventdata->userfrom->id,
|
||||
@ -181,6 +386,20 @@ class manager {
|
||||
$eventdata->courseid
|
||||
)->trigger();
|
||||
} else { // Must be a message.
|
||||
// If the message is a group conversation, then trigger the 'group_message_sent' event.
|
||||
if ($eventdata->convid) {
|
||||
$conv = $DB->get_record('message_conversations', ['id' => $eventdata->convid], 'id, type');
|
||||
if ($conv->type == \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP) {
|
||||
\core\event\group_message_sent::create_from_ids(
|
||||
$eventdata->userfrom->id,
|
||||
$eventdata->convid,
|
||||
$savemessage->id,
|
||||
$eventdata->courseid
|
||||
)->trigger();
|
||||
return;
|
||||
}
|
||||
// Individual type conversations fall through to the default 'message_sent' event.
|
||||
}
|
||||
\core\event\message_sent::create_from_ids(
|
||||
$eventdata->userfrom->id,
|
||||
$eventdata->userto->id,
|
||||
|
Loading…
x
Reference in New Issue
Block a user