Auto purge uploads from old deleted posts

Discourse already automatically removes orphan unreferenced uploads. Why not expand this functionality and erase uploads from deleted posts? Only staff members are able to see deleted posts and that is very useful. But is it really necessary to keep all the files indefinitely? As administrator I really don`t care about 2 years old deleted pictures. Some of which may even be right out against site guidelines.

It would be nice if Discourse would automatically delete these kind old files and place some kind of text block in the place of deleted file. So that it would be evident that file deletion has taken place.

For example all year old uploads which are referenced only in deleted posts would be automatically deleted.

8 лайков

Я бы тоже очень хотел этого.

Кажется, что эта функция частично реализована:

Используемые мной настройки:
clean orphan uploads grace period hours: 1
purge deleted uploads grace period days: 1

Однако удаление загрузки не включает случай, когда пост с содержащимся в нём изображением удаляется. Считается, что изображение/загрузку нужно сначала удалить из поста перед его удалением.

Могу подтвердить, что изображения не удаляются, если (единственный) пост, содержащий это конкретное изображение, был удалён. У меня есть изображения, которые до сих пор существуют в базе данных и на S3, хотя пост, в котором они были, был удалён в 2023 году (при этом изображение не использовалось ни в каких других постах). В предыдущих случаях они тоже никогда не удалялись.

Таким образом, если модератор удаляет пост из-за загруженного изображения, нарушающего правила, чтобы действительно удалить его, нужно сначала вырезать его из темы/поста (и надеяться, что оно не используется ни в каких других постах). Иначе оно будет существовать на S3 бесконечно, по крайней мере, насколько я понимаю.

Некоторые функции, которые были бы очень полезны:

  • purge deleted uploads grace period days — либо включить в эту настройку случай, когда изображение содержится в удалённом посте, либо добавить отдельную настройку для этого случая.

  • purge deleted uploads grace period days — использовать часы вместо дней. Запросы на удаление по авторским правам обычно требуют крайне оперативного реагирования, в течение 24–48 часов. Один день для этого случая слишком медленный. Кроме того, любой кэш CDN, вероятно, также нужно очищать вручную после удаления, что ещё больше сужает временные рамки.

  • Возможность удаления/очистки изображения из панели управления. Хотя, если очистка удалённых загрузок включала бы изображения внутри удалённых постов, это было бы менее необходимо, но всё ещё остаются случаи, когда изображение используется как аватар, баннер профиля и т. д., а также это было бы более эффективно для модераторов. Feature suggestion: Image removal/purge via web dashboard

  • Сделать URL-адреса изображений поисковыми. Это позволило бы модератору найти все темы/посты, содержащие конкретное изображение, чтобы удалить эти посты. Без необходимости использовать SSH.

  • Возможность блокировать определённые хэши от загрузки была бы приятным дополнением.

Это было бы удобно, так как такие процессы могли бы обрабатываться людьми без доступа к SSH и технических навыков. Особенно учитывая, насколько быстро нужно реагировать. Неприемлемо дорого иметь технический персонал, готовый 24/7 обрабатывать любые подобные случаи, включая праздники, выходные, дни болезни и т. д. Невозможно предсказать, когда это произойдёт, поэтому нужно всегда быть готовым оперативно реагировать в любой момент. Это неизбежное свойство контента, создаваемого пользователями (UGC).

2 лайка

Интересно, почему об этом не говорят шире? Это действительно серьёзная проблема.

Я написал PHP-скрипт, который использует CSV-файл, сгенерированный следующим SQL-запросом, перечисляющим все загрузки и их ссылки:
(увеличьте лимит, если у вас много загрузок)

SELECT 
    uploads.original_filename,
    ROUND(uploads.filesize / 1000000.0, 2) AS size_in_mb,
    uploads.extension,
    uploads.created_at,
    uploads.url,
    upload_references.upload_id,
    upload_references.target_id,
    upload_references.target_type,
    upload_references.created_at,
    upload_references.updated_at
FROM upload_references
JOIN uploads ON uploads.id = upload_references.upload_id
ORDER BY upload_references.target_type
LIMIT 90000

Суть работы скрипта: он фильтрует загрузки, которые остаются только как черновики (которые ошибочно сохраняются в базе данных, как я объяснял здесь). Скрипт выводит строку с пробелами, содержащую все имена файлов. Вы также можете изменить скрипт, чтобы он выводил полный путь (удалите функцию basename()).

Затем войдите на ваш сервер Discourse через SSH и выполните команду rm для всех этих файлов.

  • Один недостаток этого подхода: будут удалены все изображения, которые остаются в активных черновиках (но это можно ограничить, уменьшив значение удалять черновики старше n дней).
  • Второй недостаток: некорректные записи в базе данных всё ещё остаются; для этого мне нужно попросить разработчиков исправить проблему.

Если некорректные записи будут удалены, проблема должна быть решена окончательно.

<?php
 
if (($open = fopen("test.csv", "r")) !== false) {
    while (($data = fgetcsv($open, 100000, ",")) !== false) {
        $array[] = $data;
    }
 
    fclose($open);
}
$final = array();
$i=0;
foreach ($array as $item){
	if($item[7]=="Draft"){
			foreach ($array as $item_inside){
				if(($item_inside[4]==$item[4]) && ($item_inside[7]!="Draft")) $i++; //увеличиваем i, если есть не только черновики
				}
			if($i==0)array_push($final, $item[4]); //были только черновики, можно добавить в массив
			$i=0;
		}
	}
$final_unique= array_unique($final);
//print_r($final_unique);

foreach($final_unique as $single){
	echo basename($single)." ";
	}
?>

Файл test.csv, содержащий результат запроса, должен находиться в той же директории, что и скрипт.
Если возникнут проблемы — спрашивайте!

3 лайка

Мне кажется, многие просто не понимают, что загрузки не удаляются автоматически.

Для тех, кто хочет почитать подробнее, вот ещё одна связанная тема:

2 лайка

Я надеялся, что это уже исправлено после столького времени. Возможно, придется перепроверить, остались ли сироты на сервере. В любом случае этот скрипт — спасение.

3 лайка

Привет! Думаю, это было частично исправлено на прошлой неделе…

Теперь у нас есть автоматизация[1], которая удаляет разметку загрузок из удалённых постов. Например:

 Hey it is a regular post with a link to [Discourse](https://www.discourse.org) 
 and an image: ![logo.png|100x200](upload://gj6GJHlc1Sa5YXuGz549oXBbcFv.png)
 and a file: [small.pdf|attachment](upload://3bWzVVoRhUXxi7tiPenInoebHyX.pdf) (130 Bytes)

После выполнения автоматизации в этом посте будет следующая отредактированная версия:

 Hey it is a regular post with a link to [Discourse](https://www.discourse.org) 
 and an image:
 and a file: 

А поскольку эти загрузки теперь становятся «сиротами», они будут обработаны задачей очистки загрузок.


Кроме того, если вы используете собственное хостинг-решение, вы можете обновить директивы управления кэшем с помощью параметров s3_stale_while_revalidate и s3_max_age.


  1. Название автоматизации — «Remove upload markup in deleted posts» ↩︎

3 лайка

Это отлично! Очень хорошее решение. :slight_smile:

Интересно, имеет ли смысл использовать ту же стратегию удаления ссылок на загрузку в формате Markdown в постах для обратного сценария, когда загрузка уничтожена, но посты, ссылающиеся на неё, остаются активными.

Если я уничтожаю загрузку, например:

Upload.find(123).destroy

И если загрузка 123 использовалась пользователями для:

  • пользовательского аватара профиля
  • фона профиля
  • фона карточки

Все ссылки удаляются, по-видимому, в:

before_destroy (удаление ссылок на загрузки фона/баннера карточки)

https://github.com/discourse/discourse/blob/6759ad71cac395697b2978eb34fcfbf1162d30d1/app/models/upload.rb#L53

after_destroy (удаление ссылок на загрузки аватара)

https://github.com/discourse/discourse/blob/6759ad71cac395697b2978eb34fcfbf1162d30d1/app/models/upload.rb#L60

Если бы идентификаторы постов, связанные с идентификатором загрузки, можно было использовать для постановки в очередь удаления ссылок на загрузку в формате Markdown при её уничтожении, это, возможно, предотвратило бы появление нерабочих ссылок на загрузки в не удалённых постах при ручном уничтожении загрузки.

В идеале следует сохранять разметку Markdown для всех идентификаторов загрузок, которые не были уничтожены, например, если один пост содержит две загрузки, но уничтожена только одна.

Например, при удалении загрузки, на которую ссылаются в нескольких постах (например, в постах с цитатами), через https://meta.discourse.org/t/legal-compliance-plugin/356331 или через CLI Rails.

1 лайк