Commit 3bcf6b3c authored by Rajesh Taneja's avatar Rajesh Taneja
Browse files

MDL-31560 Messages: Added support for noreply and support users

This is used by messaging system for sending/receiving message
to/from noreply or support user. message_send api will now use
core_user class to get noreply or support user and then
send/receive message depending on user state.
parent 83f26f64
......@@ -448,6 +448,14 @@ $CFG->admin = 'admin';
// config.php file
// $CFG->preventexecpath = true;
//
// Use the following flag to set userid for noreply user. If not set then moodle will
// create dummy user and use -ve value as user id.
// $CFG->noreplyuserid = -10;
//
// As of version 2.6 Moodle supports admin to set support user. If not set, all mails
// will be sent to supportemail.
// $CFG->supportuserid = -20;
//
//=========================================================================
// 7. SETTINGS FOR DEVELOPMENT SERVERS - not intended for production use!!!
//=========================================================================
......
......@@ -10,25 +10,12 @@
redirect($CFG->wwwroot);
}
/// Work out who to send the message to
if (!$admin = get_admin() ) {
print_error('cannotfindadmin', 'debug');
}
$supportuser = new stdClass();
$supportuser->email = $CFG->supportemail ? $CFG->supportemail : $admin->email;
$supportuser->firstname = $CFG->supportname ? $CFG->supportname : $admin->firstname;
$supportuser->lastname = $CFG->supportname ? '' : $admin->lastname;
// emailstop could be hard coded "false" to ensure error reports are sent
// but then admin's would have to alter their messaging preferences to temporarily stop them
$supportuser->emailstop = $admin->emailstop;
$supportuser->maildisplay = true;
/// Send the message and redirect
// Send the message and redirect.
$eventdata = new stdClass();
$eventdata->modulename = 'moodle';
$eventdata->component = 'moodle';
$eventdata->name = 'errors';
$eventdata->userfrom = $USER;
$eventdata->userto = $supportuser;
$eventdata->userto = core_user::get_support_user();
$eventdata->subject = 'Error: '. $form->referer .' -> '. $form->requested;
$eventdata->fullmessage = $form->text;
$eventdata->fullmessageformat = FORMAT_PLAIN;
......
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* User class
*
* @package core
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* User class to access user details.
*
* @todo move api's from user/lib.php and depreciate old ones.
* @package core
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_user {
/**
* No reply user id.
*/
const NOREPLY_USER = -10;
/**
* Suppport user id.
*/
const SUPPORT_USER = -20;
/** @var stdClass keep record of noreply user */
public static $noreplyuser = false;
/** @var stdClass keep record of support user */
public static $supportuser = false;
/**
* Return user object from db or create noreply or support user,
* if userid matches corse_user::NOREPLY_USER or corse_user::SUPPORT_USER
* respectively. If userid is not found, then return false.
*
* @param int $userid user id
* @param string $fields A comma separated list of user fields to be returned, support and noreply user
* will not be filtered by this.
* @param int $strictness IGNORE_MISSING means compatible mode, false returned if user not found, debug message if more found;
* IGNORE_MULTIPLE means return first user, ignore multiple user records found(not recommended);
* MUST_EXIST means throw an exception if no user record or multiple records found.
* @return stdClass|bool user record if found, else false.
* @throws dml_exception if user record not found and respective $strictness is set.
*/
public static function get_user($userid, $fields = '*', $strictness = IGNORE_MISSING) {
global $DB;
// If noreply user then create fake record and return.
switch ($userid) {
case self::NOREPLY_USER:
return self::get_noreply_user($strictness);
break;
case self::SUPPORT_USER:
return self::get_support_user($strictness);
break;
default:
return $DB->get_record('user', array('id' => $userid), $fields, $strictness);
}
}
/**
* Helper function to return dummy noreply user record.
*
* @return stdClass
*/
protected static function get_dummy_user_record() {
global $CFG;
$dummyuser = new stdClass();
$dummyuser->id = self::NOREPLY_USER;
$dummyuser->email = $CFG->noreplyaddress;
$dummyuser->firstname = get_string('noreplyname');
$dummyuser->username = 'noreply';
$dummyuser->lastname = '';
$dummyuser->confirmed = 1;
$dummyuser->suspended = 0;
$dummyuser->deleted = 0;
$dummyuser->picture = 0;
$dummyuser->auth = 'manual';
$dummyuser->firstnamephonetic = '';
$dummyuser->lastnamephonetic = '';
$dummyuser->middlename = '';
$dummyuser->alternatename = '';
$dummyuser->imagealt = '';
return $dummyuser;
}
/**
* Return noreply user record, this is currently used in messaging
* system only for sending messages from noreply email.
* It will return record of $CFG->noreplyuserid if set else return dummy
* user object with hard-coded $user->emailstop = 1 so noreply can be sent to user.
*
* @return stdClass user record.
*/
public static function get_noreply_user() {
global $CFG;
if (!empty(self::$noreplyuser)) {
return self::$noreplyuser;
}
// If noreply user is set then use it, else create one.
if (!empty($CFG->noreplyuserid)) {
self::$noreplyuser = self::get_user($CFG->noreplyuserid);
}
if (empty(self::$noreplyuser)) {
self::$noreplyuser = self::get_dummy_user_record();
}
self::$noreplyuser->emailstop = 1; // Force msg stop for this user.
return self::$noreplyuser;
}
/**
* Return support user record, this is currently used in messaging
* system only for sending messages to support email.
* $CFG->supportuserid is set then returns user record
* $CFG->supportemail is set then return dummy record with $CFG->supportemail
* else return admin user record with hard-coded $user->emailstop = 0, so user
* gets support message.
*
* @return stdClass user record.
*/
public static function get_support_user() {
global $CFG;
if (!empty(self::$supportuser)) {
return self::$supportuser;
}
// If custom support user is set then use it, else if supportemail is set then use it, else use noreply.
if (!empty($CFG->supportuserid)) {
self::$supportuser = self::get_user($CFG->supportuserid, '*', MUST_EXIST);
}
// Try sending it to support email if support user is not set.
if (empty(self::$supportuser) && !empty($CFG->supportemail)) {
self::$supportuser = self::get_dummy_user_record();
self::$supportuser->id = self::SUPPORT_USER;
self::$supportuser->email = $CFG->supportemail;
self::$supportuser->firstname = $CFG->supportname ? $CFG->supportname : $supportuser->firstname;
self::$supportuser->username = 'support';
self::$supportuser->maildisplay = true;
}
// Send support msg to admin user if nothing is set above.
if (empty(self::$supportuser)) {
self::$supportuser = get_admin();
}
// Unset emailstop to make sure support message is sent.
self::$supportuser->emailstop = 0;
return self::$supportuser;
}
/**
* Reset self::$noreplyuser and self::$supportuser.
* This is only used by phpunit, and there is no other use case for this function.
* Please don't use it outside phpunit.
*/
public static function reset_internal_users() {
if (PHPUNIT_TEST) {
self::$noreplyuser = false;
self::$supportuser = false;
} else {
debugging('reset_internal_users() should not be used outside phpunit.', DEBUG_DEVELOPER);
}
}
/**
* Return true is user id is greater than self::NOREPLY_USER and
* alternetely check db.
*
* @param int $userid user id.
* @param bool $checkdb if true userid will be checked in db. By default it's false, and
* userid is compared with NOREPLY_USER for performance.
* @return bool true is real user else false.
*/
public static function is_real_user($userid, $checkdb = false) {
if ($userid < 0) {
return false;
}
if ($checkdb) {
return $DB->record_exists('user', array('id' => $userid));
} else {
return true;
}
}
}
......@@ -61,13 +61,21 @@ function message_send($eventdata) {
$DB->transactions_forbidden();
if (is_number($eventdata->userto)) {
$eventdata->userto = $DB->get_record('user', array('id' => $eventdata->userto));
$eventdata->userto = core_user::get_user($eventdata->userto);
}
if (is_int($eventdata->userfrom)) {
$eventdata->userfrom = $DB->get_record('user', array('id' => $eventdata->userfrom));
$eventdata->userfrom = core_user::get_user($eventdata->userfrom);
}
$usertoisrealuser = (core_user::is_real_user($eventdata->userto->id) != false);
// If recipient is internal user (noreply user), and emailstop is set then don't send any msg.
if (!$usertoisrealuser && !empty($eventdata->userto->emailstop)) {
debugging('Attempt to send msg to internal (noreply) user', DEBUG_NORMAL);
return false;
}
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));
$eventdata->userto = core_user::get_user($eventdata->userto->id);
}
//after how long inactive should the user be considered logged off?
......@@ -150,6 +158,11 @@ function message_send($eventdata) {
$preferencebase = $eventdata->component.'_'.$eventdata->name;
// Fill in the array of processors to be used based on default and user preferences
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})) {
......
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Tests core_user class.
*
* @package core
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Test core_user class.
*
* @package core
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_user_testcase extends advanced_testcase {
public function test_get_user() {
global $CFG;
$this->resetAfterTest(true);
// Create user and try fetach it with api.
$user = $this->getDataGenerator()->create_user();
$this->assertEquals($user, core_user::get_user($user->id, '*', MUST_EXIST));
// Test noreply user.
$CFG->noreplyuserid = null;
$noreplyuser = core_user::get_noreply_user();
$this->assertEquals(1, $noreplyuser->emailstop);
$this->assertFalse(core_user::is_real_user($noreplyuser->id));
$this->assertEquals($CFG->noreplyaddress, $noreplyuser->email);
$this->assertEquals(get_string('noreplyname'), $noreplyuser->firstname);
// Set user as noreply user and make sure noreply propery is set.
core_user::reset_internal_users();
$CFG->noreplyuserid = $user->id;
$noreplyuser = core_user::get_noreply_user();
$this->assertEquals(1, $noreplyuser->emailstop);
$this->assertTrue(core_user::is_real_user($noreplyuser->id));
// Test support user.
core_user::reset_internal_users();
$CFG->supportemail = null;
$CFG->noreplyuserid = null;
$supportuser = core_user::get_support_user();
$adminuser = get_admin();
$this->assertEquals($adminuser, $supportuser);
$this->assertTrue(core_user::is_real_user($supportuser->id));
// When supportemail is set.
core_user::reset_internal_users();
$CFG->supportemail = 'test@support.moodle.test';
$supportuser = core_user::get_support_user();
$this->assertEquals(core_user::SUPPORT_USER, $supportuser->id);
$this->assertFalse(core_user::is_real_user($supportuser->id));
// Set user as support user and make sure noreply propery is set.
core_user::reset_internal_users();
$CFG->supportuserid = $user->id;
$supportuser = core_user::get_support_user();
$this->assertEquals($user, $supportuser);
$this->assertTrue(core_user::is_real_user($supportuser->id));
}
}
......@@ -32,6 +32,9 @@ information provided here is intended especially for developers.
get_fast_modinfo(). Purging all caches and every core upgrade purges course modinfo cache as well.
If function get_fast_modinfo() is called for multiple courses make sure to include field cacherev in course
object.
* Internal (noreply and support) user support has been added for sending/receiving message.
Use core_user::get_noreply_user() and core_user::get_support_user() to get noreply and support user's respectively.
Real users can be used as noreply/support users by setting $CFG->noreplyuserid and $CFG->supportuserid
DEPRECATIONS:
Various previously deprecated functions have now been altered to throw DEBUG_DEVELOPER debugging notices
......@@ -104,6 +107,7 @@ Misc:
* js_minify() -> core_minify::js_files()
* css_minify_css() -> core_minify::css_files()
* course_modinfo::build_section_cache() -> (no replacement)
* generate_email_supportuser() -> core_user::get_support_user()
User-agent related functions:
* check_browser_operating_system() -> core_useragent::check_browser_operating_system()
......
......@@ -103,13 +103,15 @@ unset($user1id);
$user2 = null;
if (!empty($user2id)) {
$user2 = $DB->get_record("user", array("id" => $user2id));
$user2 = core_user::get_user($user2id);
if (!$user2) {
print_error('invaliduserid');
}
}
unset($user2id);
$user2realuser = !empty($user2) && core_user::is_real_user($user2->id);
$showactionlinks = $showactionlinks && $user2realuser;
$systemcontext = context_system::instance();
if (!empty($user2) && $user1->id == $user2->id) {
......@@ -159,7 +161,7 @@ if ($unblockcontact and confirm_sesskey()) {
//was a message sent? Do NOT allow someone looking at someone else's messages to send them.
$messageerror = null;
if ($currentuser && !empty($user2) && has_capability('moodle/site:sendmessage', $systemcontext)) {
if ($currentuser && $user2realuser && has_capability('moodle/site:sendmessage', $systemcontext)) {
// Check that the user is not blocking us!!
if ($contact = $DB->get_record('message_contacts', array('userid' => $user2->id, 'contactid' => $user1->id))) {
if ($contact->blocked and !has_capability('moodle/site:readallmessages', $systemcontext)) {
......@@ -199,7 +201,7 @@ if ($currentuser && !empty($user2) && has_capability('moodle/site:sendmessage',
}
$strmessages = get_string('messages', 'message');
if (!empty($user2)) {
if ($user2realuser) {
$user2fullname = fullname($user2);
$PAGE->set_title("$strmessages: $user2fullname");
......@@ -219,7 +221,7 @@ $countunreadtotal = 0; //count of unread messages from all users
//we're dealing with unread messages early so the contact list will accurately reflect what is read/unread
$viewingnewmessages = false;
if (!empty($user2)) {
if ($user2realuser) {
//are there any unread messages from $user2
$countunread = message_count_unread_messages($user1, $user2);
if ($countunread>0) {
......@@ -247,7 +249,7 @@ list($onlinecontacts, $offlinecontacts, $strangers) = message_get_contacts($user
message_print_contact_selector($countunreadtotal, $viewing, $user1, $user2, $blockedusers, $onlinecontacts, $offlinecontacts, $strangers, $showactionlinks, $page);
echo html_writer::start_tag('div', array('class' => 'messagearea mdl-align'));
if (!empty($user2)) {
if ($user2realuser) {
echo html_writer::start_tag('div', array('class' => 'mdl-left messagehistory'));
......
......@@ -1198,7 +1198,7 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
// Load user-to record.
if ($message->useridto !== $USER->id) {
$userto = $DB->get_record('user', array('id' => $message->useridto));
$userto = core_user::get_user($message->useridto);
$tocontact = (array_key_exists($message->useridto, $contacts) and
($contacts[$message->useridto]->blocked == 0) );
$toblocked = (array_key_exists($message->useridto, $contacts) and
......@@ -1211,7 +1211,7 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
// Load user-from record.
if ($message->useridfrom !== $USER->id) {
$userfrom = $DB->get_record('user', array('id' => $message->useridfrom));
$userfrom = core_user::get_user($message->useridfrom);
$fromcontact = (array_key_exists($message->useridfrom, $contacts) and
($contacts[$message->useridfrom]->blocked == 0) );
$fromblocked = (array_key_exists($message->useridfrom, $contacts) and
......@@ -1294,10 +1294,16 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
function message_print_user ($user=false, $iscontact=false, $isblocked=false, $includeicontext=false) {
global $USER, $OUTPUT;
$userpictureparams = array('size' => 20, 'courseid' => SITEID);
if ($user === false) {
echo $OUTPUT->user_picture($USER, array('size' => 20, 'courseid' => SITEID));
echo $OUTPUT->user_picture($USER, $userpictureparams);
} else if (core_user::is_real_user($user->id)) { // If not real user, then don't show any links.
$userpictureparams['link'] = false;
echo $OUTPUT->user_picture($USER, $userpictureparams);
echo fullname($user);
} else {
echo $OUTPUT->user_picture($user, array('size' => 20, 'courseid' => SITEID));
echo $OUTPUT->user_picture($user, $userpictureparams);
$link = new moodle_url("/message/index.php?id=$user->id");
echo $OUTPUT->action_link($link, fullname($user), null, array('title' =>
......
......@@ -127,4 +127,13 @@ class message_output_email extends message_output {
function load_data(&$preferences, $userid){
$preferences->email_email = get_user_preferences( 'message_processor_email_email', '', $userid);
}
/**
* Returns true as message can be sent to internal support user.
*
* @return bool
*/
public function can_send_to_any_users() {
return true;
}
}
......@@ -92,6 +92,16 @@ abstract class message_output {
public function get_default_messaging_settings() {
return MESSAGE_PERMITTED;
}
/**
* Returns true if message can be sent to fake/internal user as well.
* If message_output support message to be sent to fake user, then it should return true, like email.
*
* @return bool
*/
public function can_send_to_any_users() {
return false;
}
}
......
This files describes API changes in /message/ messaging system,
information provided here is intended especially for developers.
=== 2.6 ===
* Message processor extending message_output, should return true in can_send_to_any_users()
if it supports message sending to internal (noreply/support) users.
=== 2.2 ===
required changes:
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment