Script: Add script to delete old messages & add exception mgmt to message lib - refs BT#19984

pull/4343/head
Yannick Warnier 3 years ago
parent 84c6fa0b61
commit e0b11f7070
  1. 74
      main/inc/lib/message.lib.php
  2. 1
      main/inc/lib/social.lib.php
  3. 127
      tests/scripts/delete_old_messages.php

@ -921,16 +921,17 @@ class MessageManager
}
/**
* @param int $user_receiver_id
* @param int $id
* Delete (or just flag) a message (and its attachment) from the table and disk
* @param int The owner (receiver) of the message
* @param int The internal ID of the message
* @param bool Whether to really delete the message (true) or just mark it deleted (default/false)
*
* @return bool
* @return bool False on error, true otherwise
* @throws Exception if file cannot be deleted in delete_message_attachment_file()
*/
public static function delete_message_by_user_receiver($user_receiver_id, $id)
public static function delete_message_by_user_receiver(int $user_receiver_id, int $id, bool $realDelete = false)
{
$table = Database::get_main_table(TABLE_MESSAGE);
$id = (int) $id;
$user_receiver_id = (int) $user_receiver_id;
if (empty($id) || empty($user_receiver_id)) {
return false;
@ -945,13 +946,18 @@ class MessageManager
if (Database::num_rows($rs) > 0) {
// Delete attachment file.
self::delete_message_attachment_file($id, $user_receiver_id);
self::delete_message_attachment_file($id, $user_receiver_id, null, $realDelete);
if (false !== $realDelete) {
// Hard delete message.
$query = "DELETE FROM $table WHERE id = $id";
} else {
// Soft delete message.
$query = "UPDATE $table
SET msg_status = ".MESSAGE_STATUS_DELETED."
WHERE
id = $id AND
user_receiver_id = $user_receiver_id ";
}
Database::query($query);
return true;
@ -961,20 +967,19 @@ class MessageManager
}
/**
* Set status deleted.
* Set status deleted or delete the message completely
*
* @author Isaac FLores Paz <isaac.flores@dokeos.com>
*
* @param int
* @param int
* @author Yannick Warnier <yannick.warnier@beeznest.com> - Added realDelete option
* @param int The user's sender ID
* @param int The message's ID
* @param bool whether to really delete the message (true) or just mark it deleted (default/false)
*
* @return bool
* @throws Exception if file cannot be deleted in delete_message_attachment_file()
*/
public static function delete_message_by_user_sender($user_sender_id, $id)
public static function delete_message_by_user_sender(int $user_sender_id, int $id, bool $realDelete = false)
{
$user_sender_id = (int) $user_sender_id;
$id = (int) $id;
if (empty($id) || empty($user_sender_id)) {
return false;
}
@ -986,11 +991,16 @@ class MessageManager
if (Database::num_rows($rs) > 0) {
// delete attachment file
self::delete_message_attachment_file($id, $user_sender_id);
// delete message
self::delete_message_attachment_file($id, $user_sender_id, null, $realDelete);
if (false !== $realDelete) {
// hard delete message
$sql = "DELETE FROM $table WHERE id = $id";
} else {
// soft delete message
$sql = "UPDATE $table
SET msg_status = '".MESSAGE_STATUS_DELETED."'
WHERE user_sender_id = $user_sender_id AND id = $id";
}
Database::query($sql);
return true;
@ -1094,22 +1104,25 @@ class MessageManager
* @param int message id
* @param int message user id (receiver user id or sender user id)
* @param int group id (optional)
* @param bool whether to really delete the file (true) or just mark it deleted (default/false)
* @return void
* @throws Exception if file cannot be deleted
*/
public static function delete_message_attachment_file(
$message_id,
$message_uid,
$group_id = 0
) {
$message_id = (int) $message_id;
$message_uid = (int) $message_uid;
int $message_id,
int $message_uid,
?int $group_id = 0,
bool $realDelete = false
): void
{
$table_message_attach = Database::get_main_table(TABLE_MESSAGE_ATTACHMENT);
$sql = "SELECT * FROM $table_message_attach
WHERE message_id = '$message_id'";
WHERE message_id = $message_id";
$rs = Database::query($sql);
while ($row = Database::fetch_array($rs)) {
$path = $row['path'];
$attach_id = (int) $row['id'];
$attach_id = $row['id'];
$new_path = $path.'_DELETED_'.$attach_id;
if (!empty($group_id)) {
@ -1128,13 +1141,22 @@ class MessageManager
$path_message_attach = $path_user_info['dir'].'message_attachments/';
if (is_file($path_message_attach.$path)) {
if ($realDelete) {
$unlink = unlink($path_message_attach.$path);
if (!$unlink) {
throw new Exception('Could not delete file '.$path_message_attach.$path);
}
$sql = "DELETE FROM $table_message_attach
WHERE id = $attach_id ";
} else {
if (rename($path_message_attach.$path, $path_message_attach.$new_path)) {
$sql = "UPDATE $table_message_attach
SET path = '$new_path'
WHERE id = $attach_id ";
Database::query($sql);
}
}
Database::query($sql);
}
}
}

@ -2124,6 +2124,7 @@ class SocialManager extends UserManager
* @param int $id id message to delete
*
* @return bool status query
* @throws Exception if file cannot be deleted in delete_message_attachment_file()
*/
public static function deleteMessage($id)
{

@ -0,0 +1,127 @@
<?php
/* For licensing terms, see /license.txt */
/**
* This script removes old messages from the database and disk.
* It uses parameters in order (all mandatory but the last one).
* Delete the exit; statement at line 13.
* This script must be launched as root or another privileged user to be
* able to delete files on disk (created by the web server)
* This script should be located inside the tests/scripts/ folder to work
* @author Yannick Warnier <yannick.warnier@beeznest.com>
*/
exit;
require __DIR__.'/../../main/inc/global.inc.php';
$simulate = false;
// Process script parameters
if (PHP_SAPI !== 'cli') {
die('This script can only be executed from the command line');
}
if (!empty($argv[1]) && $argv[1] == '-s') {
$simulate = true;
echo "Simulation mode is enabled".PHP_EOL;
}
if (!empty($argv[1]) && $argv[1] == '--from') {
$from = $argv[2];
}
if (!empty($argv[3]) && $argv[3] == '--until') {
$until = $argv[4];
}
if (empty($from) or empty($until)) {
echo PHP_EOL."Usage: sudo php ".basename(__FILE__)." [options]".PHP_EOL;
echo "Where [options] can be ".PHP_EOL;
echo " --from yyyy-mm-dd Date from which the content should be removed (e.g. 2017-08-31)".PHP_EOL.PHP_EOL;
echo " --until yyyy-mm-dd Date up to which the content should be removed (e.g. 2020-08-31)".PHP_EOL.PHP_EOL;
echo " -s (optional) Simulate execution - Do not delete anything, just show numbers".PHP_EOL.PHP_EOL;
die('Please make sure --from and --until are defined.');
}
echo "About to delete messages from $from to $until".PHP_EOL;
echo deleteMessages($from, $until, $simulate);
/**
* Delete messages between the given dates and return a log string.
* @param string $from 'yyyy-mm-dd' format date from which to start deleting
* @param string $until 'yyyy-mm-dd' format date until which to delete
* @param bool $simulate True if we only want to simulate the deletion and collect data
* @return string
*/
function deleteMessages(string $from, string $until, bool $simulate): string
{
$log = '';
$size = 0;
if ($simulate) {
$log .= 'Simulation mode ON'.PHP_EOL;
}
$messages = getMessagesInDateRange($from, $until);
$log .= 'Found '.count($messages).' matching messages'.PHP_EOL;
$count = count($messages);
foreach ($messages as $message) {
$log .= "Deleting message ".$message['id'].PHP_EOL;
$attachment = MessageManager::getAttachment($message['id']);
if (false !== $attachment) {
$log .= 'Msg '.$message['id'].' has attachment'.PHP_EOL;
$size += $attachment['size'];
}
if (!$simulate) {
$log .= 'Deleting '.$message['id'].' for receiver '.$message['user_receiver_id'].PHP_EOL;
try {
$result = MessageManager::delete_message_by_user_receiver(
$message['user_receiver_id'],
$message['id'],
true
);
} catch (Exception $e) {
echo $e->getMessage();
die('Process interrupted because not being able to delete file (permissions issues?) will generate a consistency loss and be difficult to fix. Please use "sudo" or other similar mechanism to ensure the user launching this script is allowed to delete the mentionned file.');
}
}
if ($result || $simulate) {
$log .= 'Deleted msg id '.str_pad($message['id'], 9, ' ', STR_PAD_LEFT).' in receiver\'s box'.PHP_EOL;
}
if (!$simulate) {
$log .= 'Deleting '.$message['id'].' for sender '.$message['user_sender_id'].PHP_EOL;
try {
$result = MessageManager::delete_message_by_user_sender(
$message['user_sender_id'],
$message['id'],
true
);
} catch (Exception $e) {
echo $e->getMessage();
die('Process interrupted because not being able to delete file (permissions issues?) will generate a consistency loss and be difficult to fix. Please use "sudo" or other similar mechanism to ensure the user launching this script is allowed to delete the mentionned file.');
}
}
if ($result || $simulate) {
$log .= 'Deleted msg id '.str_pad($message['id'], 9, ' ', STR_PAD_LEFT).' in sender\'s box'.PHP_EOL;
}
}
$log .= 'In total, '.$size.'B were freed together with '.$count.' messages.'.PHP_EOL;
return $log;
}
/**
* Get a list of messages IDs between the given dates (sent or received, equally)
* @param string $from
* @param string $until
* @return array
*/
function getMessagesInDateRange(string $from, string $until): array
{
$messages = [];
$sql = 'SELECT id, user_sender_id, user_receiver_id, group_id
FROM '.Database::get_main_table(TABLE_MESSAGE).'
WHERE send_date > "'.$from.' 00:00:00" AND send_date < "'.$until.' 23:59:59"';
$res = Database::query($sql);
if (Database::num_rows($res) > 0) {
while ($row = Database::fetch_assoc($res)) {
$messages[] = $row;
}
}
return $messages;
}
Loading…
Cancel
Save