Skip to content

Commit

Permalink
MDL-29801 core_message: added ability to delete messages
Browse files Browse the repository at this point in the history
Thanks goes to Jetha for providing the HTML and CSS.
  • Loading branch information
mdjnelson committed Sep 2, 2015
1 parent 4582308 commit 36d29c0
Show file tree
Hide file tree
Showing 12 changed files with 600 additions and 15 deletions.
2 changes: 2 additions & 0 deletions lang/en/message.php
Expand Up @@ -41,6 +41,8 @@
$string['context'] = 'context';
$string['defaultmessageoutputs'] = 'Default message outputs';
$string['defaults'] = 'Defaults';
$string['deletemessage'] = 'Delete message';
$string['deletemessageconfirmation'] = 'Are you sure you want to delete this message? It will only be deleted from your messaging history and will still be viewable by the user who sent or received the message.';
$string['deletemessagesdays'] = 'Number of days before old messages are automatically deleted';
$string['disableall'] = 'Temporarily disable notifications';
$string['disableall_help'] = 'Temporarily disable all notifications except those marked as "forced" by the site administrator';
Expand Down
39 changes: 39 additions & 0 deletions message/index.php
Expand Up @@ -57,6 +57,11 @@
$removecontact = optional_param('removecontact', 0, PARAM_INT); // removing a contact
$blockcontact = optional_param('blockcontact', 0, PARAM_INT); // blocking a contact
$unblockcontact = optional_param('unblockcontact', 0, PARAM_INT); // unblocking a contact
$deletemessageid = optional_param('deletemessageid', 0, PARAM_INT);
$deletemessageconfirm = optional_param('deletemessageconfirm', 0, PARAM_BOOL);
if ($deletemessageid) {
$deletemessagetype = required_param('deletemessagetype', PARAM_ALPHAEXT);
}

//for search
$advancedsearch = optional_param('advanced', 0, PARAM_INT);
Expand Down Expand Up @@ -135,6 +140,17 @@
$PAGE->navigation->extend_for_user($user2);
}

$strmessages = get_string('messages', 'message');
if ($user2realuser) {
$user2fullname = fullname($user2);

$PAGE->set_title("$strmessages: $user2fullname");
$PAGE->set_heading("$strmessages: $user2fullname");
} else {
$PAGE->set_title("{$SITE->shortname}: $strmessages");
$PAGE->set_heading("{$SITE->shortname}: $strmessages");
}

/// Process any contact maintenance requests there may be
if ($addcontact and confirm_sesskey()) {
message_add_contact($addcontact);
Expand All @@ -149,6 +165,29 @@
if ($unblockcontact and confirm_sesskey()) {
message_unblock_contact($unblockcontact);
}
if ($deletemessageid and confirm_sesskey()) {
// Check that the message actually exists.
if ($message = $DB->get_record($deletemessagetype, array('id' => $deletemessageid))) {
// Check that we are allowed to delete this message.
if (message_can_delete_message($message, $user1->id)) {
if (!$deletemessageconfirm) {
$confirmurl = new moodle_url('/message/index.php', array('user1' => $user1->id, 'user2' => $user2->id,
'viewing' => $viewing, 'deletemessageid' => $message->id, 'deletemessagetype' => $deletemessagetype,
'deletemessageconfirm' => 1, 'sesskey' => sesskey()));
$confirmbutton = new single_button($confirmurl, get_string('delete'), 'post');
$strdeletemessage = get_string('deletemessage', 'message');
$PAGE->set_title($strdeletemessage);
echo $OUTPUT->header();
echo $OUTPUT->heading($strdeletemessage);
echo $OUTPUT->confirm(get_string('deletemessageconfirmation', 'message'), $confirmbutton, $url);
echo $OUTPUT->footer();
exit();
}
message_delete_message($message, $user1->id);
}
}
redirect($url);
}

//was a message sent? Do NOT allow someone looking at someone else's messages to send them.
$messageerror = null;
Expand Down
137 changes: 129 additions & 8 deletions message/lib.php
Expand Up @@ -748,11 +748,18 @@ function message_get_recent_conversations($user, $limitfrom=0, $limitto=100) {
recentmessages.useridfrom,
recentmessages.useridto
FROM {message_read} recentmessages
WHERE (recentmessages.useridfrom = :userid1 OR recentmessages.useridto = :userid2)
WHERE (
(recentmessages.useridfrom = :userid1 AND recentmessages.timeuserfromdeleted = 0) OR
(recentmessages.useridto = :userid2 AND recentmessages.timeusertodeleted = 0)
)
GROUP BY recentmessages.useridfrom, recentmessages.useridto
) recent ON matchedmessage.useridto = recent.useridto
AND matchedmessage.useridfrom = recent.useridfrom
AND matchedmessage.timecreated = recent.timecreated
WHERE (
(matchedmessage.useridfrom = :userid6 AND matchedmessage.timeuserfromdeleted = 0) OR
(matchedmessage.useridto = :userid7 AND matchedmessage.timeusertodeleted = 0)
)
GROUP BY matchedmessage.useridto, matchedmessage.useridfrom
) messagesubset ON messagesubset.messageid = message.id
JOIN {user} otheruser ON (message.useridfrom = :userid4 AND message.useridto = otheruser.id)
Expand All @@ -766,6 +773,8 @@ function message_get_recent_conversations($user, $limitfrom=0, $limitto=100) {
'userid3' => $user->id,
'userid4' => $user->id,
'userid5' => $user->id,
'userid6' => $user->id,
'userid7' => $user->id
);
$read = $DB->get_records_sql($sql, $params, $limitfrom, $limitto);

Expand Down Expand Up @@ -1136,6 +1145,78 @@ function message_block_contact($contactid) {
return message_add_contact($contactid, 1);
}

/**
* Checks if a user can delete a message.
*
* @param stdClass $message the message to delete
* @param string $userid the user id of who we want to delete the message for (this may be done by the admin
* but will still seem as if it was by the user)
* @return bool Returns true if a user can delete the message, false otherwise.
*/
function message_can_delete_message($message, $userid) {
global $USER;

if ($message->useridfrom == $userid) {
$userdeleting = 'useridfrom';
} else if ($message->useridto == $userid) {
$userdeleting = 'useridto';
} else {
return false;
}

$systemcontext = context_system::instance();

// Let's check if the user is allowed to delete this message.
if (has_capability('moodle/site:deleteanymessage', $systemcontext) ||
((has_capability('moodle/site:deleteownmessage', $systemcontext) &&
$USER->id == $message->$userdeleting))) {
return true;
}

return false;
}

/**
* Deletes a message.
*
* This function does not verify any permissions.
*
* @param stdClass $message the message to delete
* @param string $userid the user id of who we want to delete the message for (this may be done by the admin
* but will still seem as if it was by the user)
* @return bool
*/
function message_delete_message($message, $userid) {
global $DB;

// The column we want to alter.
if ($message->useridfrom == $userid) {
$coltimedeleted = 'timeuserfromdeleted';
} else if ($message->useridto == $userid) {
$coltimedeleted = 'timeusertodeleted';
} else {
return false;
}

// Don't update it if it's already been deleted.
if ($message->$coltimedeleted > 0) {
return false;
}

// Get the table we want to update.
if (isset($message->timeread)) {
$messagetable = 'message_read';
} else {
$messagetable = 'message';
}

// Mark the message as deleted.
$updatemessage = new stdClass();
$updatemessage->id = $message->id;
$updatemessage->$coltimedeleted = time();
return $DB->update_record($messagetable, $updatemessage);
}

/**
* Load a user's contact record
*
Expand Down Expand Up @@ -1791,6 +1872,18 @@ function message_search($searchterms, $fromme=true, $tome=true, $courseid='none'
// b. Messages to user
// c. Messages to and from user

if ($fromme && $tome) {
$searchcond .= " AND ((useridto = :useridto AND timeusertodeleted = 0) OR
(useridfrom = :useridfrom AND timeuserfromdeleted = 0))";
$params['useridto'] = $userid;
$params['useridfrom'] = $userid;
} else if ($fromme) {
$searchcond .= " AND (useridfrom = :useridfrom AND timeuserfromdeleted = 0)";
$params['useridfrom'] = $userid;
} else if ($tome) {
$searchcond .= " AND (useridto = :useridto AND timeusertodeleted = 0)";
$params['useridto'] = $userid;
}
if ($courseid == SITEID) { // Admin is searching all messages.
$m_read = $DB->get_records_sql("SELECT m.id, m.useridto, m.useridfrom, m.smallmessage, m.fullmessage, m.timecreated
FROM {message_read} m
Expand Down Expand Up @@ -1977,16 +2070,16 @@ function message_get_history($user1, $user2, $limitnum=0, $viewingnewmessages=fa
//prevent notifications of your own actions appearing in your own message history
$ownnotificationwhere = ' AND NOT (useridfrom=? AND notification=1)';

if ($messages_read = $DB->get_records_select('message_read', "((useridto = ? AND useridfrom = ?) OR
(useridto = ? AND useridfrom = ?)) $notificationswhere $ownnotificationwhere",
$sql = "((useridto = ? AND useridfrom = ? AND timeusertodeleted = 0) OR
(useridto = ? AND useridfrom = ? AND timeuserfromdeleted = 0))";
if ($messages_read = $DB->get_records_select('message_read', $sql . $notificationswhere . $ownnotificationwhere,
array($user1->id, $user2->id, $user2->id, $user1->id, $user1->id),
"timecreated $sort", '*', 0, $limitnum)) {
foreach ($messages_read as $message) {
$messages[] = $message;
}
}
if ($messages_new = $DB->get_records_select('message', "((useridto = ? AND useridfrom = ?) OR
(useridto = ? AND useridfrom = ?)) $ownnotificationwhere",
if ($messages_new = $DB->get_records_select('message', $sql . $ownnotificationwhere,
array($user1->id, $user2->id, $user2->id, $user1->id, $user1->id),
"timecreated $sort", '*', 0, $limitnum)) {
foreach ($messages_new as $message) {
Expand Down Expand Up @@ -2016,7 +2109,13 @@ function message_get_history($user1, $user2, $limitnum=0, $viewingnewmessages=fa
* @param bool $viewingnewmessages are we currently viewing new messages?
*/
function message_print_message_history($user1, $user2 ,$search = '', $messagelimit = 0, $messagehistorylink = false, $viewingnewmessages = false, $showactionlinks = true) {
global $CFG, $OUTPUT;
global $OUTPUT, $PAGE;

$PAGE->requires->yui_module(
array('moodle-core_message-toolbox'),
'M.core_message.toolbox.deletemsg.init',
array(array())
);

echo $OUTPUT->box_start('center', 'message_user_pictures');
echo $OUTPUT->box_start('user');
Expand Down Expand Up @@ -2069,7 +2168,9 @@ function message_print_message_history($user1, $user2 ,$search = '', $messagelim
$current->year = '';
$messagedate = get_string('strftimetime');
$blockdate = get_string('strftimedaydate');
$messagenumber = 0;
foreach ($messages as $message) {
$messagenumber++;
if ($message->notification) {
$notificationclass = ' notification';
} else {
Expand All @@ -2087,15 +2188,35 @@ function message_print_message_history($user1, $user2 ,$search = '', $messagelim
$tablecontents .= $OUTPUT->heading(userdate($message->timecreated, $blockdate), 4, 'mdl-align');
}

$formatted_message = $side = null;
if ($message->useridfrom == $user1->id) {
$formatted_message = message_format_message($message, $messagedate, $search, 'me');
$side = 'left';
} else {
$formatted_message = message_format_message($message, $messagedate, $search, 'other');
$side = 'right';
}
$tablecontents .= html_writer::tag('div', $formatted_message, array('class' => "mdl-left $side $notificationclass"));

// Check if it is a read message or not.
if (isset($message->timeread)) {
$type = 'message_read';
} else {
$type = 'message';
}

if (message_can_delete_message($message, $user1->id)) {
$usergroup = optional_param('usergroup', MESSAGE_VIEW_UNREAD_MESSAGES, PARAM_ALPHANUMEXT);
$viewing = optional_param('viewing', $usergroup, PARAM_ALPHANUMEXT);
$deleteurl = new moodle_url('/message/index.php', array('user1' => $user1->id, 'user2' => $user2->id,
'viewing' => $viewing, 'deletemessageid' => $message->id, 'deletemessagetype' => $type,
'sesskey' => sesskey()));

$deleteicon = $OUTPUT->action_icon($deleteurl, new pix_icon('t/delete', get_string('delete')));
$deleteicon = html_writer::tag('div', $deleteicon, array('class' => 'deleteicon accesshide'));
$formatted_message .= $deleteicon;
}

$tablecontents .= html_writer::tag('div', $formatted_message, array('class' => "mdl-left messagecontent
$side $notificationclass", 'id' => 'message_' . $messagenumber));
}

echo html_writer::nonempty_tag('div', $tablecontents, array('class' => 'mdl-left messagehistory'));
Expand Down
@@ -0,0 +1,118 @@
YUI.add('moodle-core_message-toolbox', function (Y, NAME) {

// 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/>.

/**
* JS used when deleting messages.
*
* @module moodle-core_message-toolbox
* @package core_message
* @copyright 2015 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

var CSS = {
ACCESSHIDE: 'accesshide',
MESSAGEACTIVE: 'messageactive'
};
var SELECTORS = {
DELETEICON: '.deleteicon',
MESSAGEACTIVE: '.messageactive',
MESSAGEHISTORY: '.messagehistory',
MESSAGES: '.messagecontent'
};

M.core_message = M.core_message || {};
M.core_message.toolbox = M.core_message.toolbox || {};

/**
* This class contains the JS related to deleting messages.
*
* @class M.core_message.toolbox.deletemsg
* @constructor
*/
M.core_message.toolbox.deletemsg = {

/**
* The area the messages are contained.
*
* @property messagearea
*/
messagearea: null,

/**
* Initializer.
*
* Sets up event listeners which 'activate' and 'deactivate' a message.
*
* @method init
*/
init: function() {
this.messagearea = Y.one(SELECTORS.MESSAGEHISTORY);

// Set the events.
this.messagearea.delegate('hover', this.over, this.out, SELECTORS.MESSAGES);
this.messagearea.delegate('click', this.click, SELECTORS.MESSAGES, this);
},

/**
* Handles when a mouse hovers over a message.
*
* @private
* @params {EventFacade} e
* @method over
*/
over: function(e) {
// 'Activate' the message area we hovered on.
e.currentTarget.addClass(CSS.MESSAGEACTIVE);
e.currentTarget.one(SELECTORS.DELETEICON).removeClass(CSS.ACCESSHIDE);
},

/**
* Handles when a mouse hovers off a message.
*
* @private
* @params {EventFacade} e
* @method out
*/
out: function(e) {
// 'Deactivate' the message area we hovered off.
e.currentTarget.removeClass(CSS.MESSAGEACTIVE);
e.currentTarget.one(SELECTORS.DELETEICON).addClass(CSS.ACCESSHIDE);
},

/**
* Handles when a mouse clicks on a message.
*
* @private
* @params {EventFacade} e
* @method click
*/
click: function(e) {
// 'Deactivate' the currently active message (if there is one).
var activemessage = this.messagearea.one(SELECTORS.MESSAGEACTIVE);
if (activemessage) {
activemessage.removeClass(CSS.MESSAGEACTIVE);
activemessage.one(SELECTORS.DELETEICON).addClass(CSS.ACCESSHIDE);
}
// 'Activate' the message area we clicked on.
e.currentTarget.addClass(CSS.MESSAGEACTIVE);
e.currentTarget.one(SELECTORS.DELETEICON).removeClass(CSS.ACCESSHIDE);
}
};


}, '@VERSION@');

0 comments on commit 36d29c0

Please sign in to comment.