Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion extend.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Flarum\Gdpr\Extend\UserData;
use Flarum\Post\Event\Posted;
use Flarum\Post\Event\Revised;
use Flarum\Post\Post;
use Flarum\Search\Database\DatabaseSearchDriver;
use Flarum\Settings\Event\Deserializing;
use Flarum\Settings\SettingsRepositoryInterface;
Expand Down Expand Up @@ -132,6 +133,8 @@
->listen(Revised::class, Listeners\LinkFilesToPostOnSave::class)
->listen(WillBeUploaded::class, Listeners\AddImageProcessor::class),

new Extend\ModelObserver(Post::class, Listeners\CleanUpFilesOnPostDelete::class),

Check failure on line 136 in extend.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.4

Instantiated class Flarum\Extend\ModelObserver not found.

Check failure on line 136 in extend.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.3

Instantiated class Flarum\Extend\ModelObserver not found.

Check failure on line 136 in extend.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.5

Instantiated class Flarum\Extend\ModelObserver not found.

Check failure on line 136 in extend.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.2

Instantiated class Flarum\Extend\ModelObserver not found.

(new Extend\Filesystem())
->disk('private-shared', Extenders\PrivateSharedDiskConfig::class),

Expand Down Expand Up @@ -162,7 +165,8 @@
->default('fof-upload.svgAnimateAllowed', false)
->default('fof-upload.generateThumbnails', true)
->default('fof-upload.thumbnailWebp', true)
->default('fof-upload.thumbnailMaxWidth', 1000),
->default('fof-upload.thumbnailMaxWidth', 1000)
->default('fof-upload.deleteFilesOnPostDelete', false),

new Extenders\AddPostDownloadTags(),
new Extenders\CreateStorageFolder('tmp'),
Expand Down
8 changes: 8 additions & 0 deletions js/src/admin/components/UploadPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export default class UploadPage extends ExtensionPage<ExtensionPageAttrs> {
'addsWatermarks',
'disableHotlinkProtection',
'disableDownloadLogging',
'deleteFilesOnPostDelete',
'awsS3UsePathStyleEndpoint',
'svgAnimateAllowed',
];
Expand Down Expand Up @@ -479,6 +480,13 @@ export default class UploadPage extends ExtensionPage<ExtensionPageAttrs> {
{app.translator.trans('fof-upload.admin.labels.disable-download-logging.toggle')}
</Switch>
</div>
<legend>{app.translator.trans('fof-upload.admin.labels.delete-files-on-post-delete.title')}</legend>
<p className="helpText">{app.translator.trans('fof-upload.admin.help_texts.delete-files-on-post-delete')}</p>
<div className="Form-group">
<Switch state={this.values.deleteFilesOnPostDelete() || false} onchange={this.values.deleteFilesOnPostDelete}>
{app.translator.trans('fof-upload.admin.labels.delete-files-on-post-delete.toggle')}
</Switch>
</div>
</fieldset>

{!this.uploadLocalCdnSetByEnv && (
Expand Down
7 changes: 7 additions & 0 deletions resources/locale/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ fof-upload:
title: Upload
description: Set up uploading services and preferences.
help_texts:
delete-files-on-post-delete: |
When enabled, files exclusively attached to a deleted post are immediately removed from storage and the database.
Files referenced by multiple posts are not affected. When disabled (default), orphaned files are only removed
when the cleanup command is run manually: php flarum fof:upload --cleanup
disable-download-logging: |
Disable logging every download made by users of your forum. Keeping it enabled allows you to view the number of downloads and other metrics in the nearby future.
disable-hotlink-protection: |
Expand Down Expand Up @@ -67,6 +71,9 @@ fof-upload:
use_path_style_endpoint: Use path style endpoint
acl: Access Control List (ACL)
custom_url: Custom S3 URL
delete-files-on-post-delete:
title: File cleanup on post deletion
toggle: Delete uploaded files when the containing post is deleted
disable-download-logging:
title: Disable logging downloads
toggle: Disable
Expand Down
58 changes: 58 additions & 0 deletions src/Listeners/CleanUpFilesOnPostDelete.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

/*
* This file is part of fof/upload.
*
* Copyright (c) FriendsOfFlarum.
* Copyright (c) Flagrow.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace FoF\Upload\Listeners;

use Flarum\Post\Post;
use Flarum\Settings\SettingsRepositoryInterface;
use FoF\Upload\Adapters\Manager;

class CleanUpFilesOnPostDelete
{
public function __construct(
private SettingsRepositoryInterface $settings,
private Manager $manager,
) {
}

/**
* Fires before the post is deleted (and before the DB cascade removes pivot rows),
* so we can still read which files are associated with this post.
*/
public function deleting(Post $post): void
{
if (!$this->settings->get('fof-upload.deleteFilesOnPostDelete', false)) {
return;
}

// Load files now — before the cascade wipes the fof_upload_file_posts rows.
$files = $post->files()

Check failure on line 38 in src/Listeners/CleanUpFilesOnPostDelete.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.4

Call to an undefined method Flarum\Post\Post::files().

Check failure on line 38 in src/Listeners/CleanUpFilesOnPostDelete.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.3

Call to an undefined method Flarum\Post\Post::files().

Check failure on line 38 in src/Listeners/CleanUpFilesOnPostDelete.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.5

Call to an undefined method Flarum\Post\Post::files().

Check failure on line 38 in src/Listeners/CleanUpFilesOnPostDelete.php

View workflow job for this annotation

GitHub Actions / run / PHPStan PHP 8.2

Call to an undefined method Flarum\Post\Post::files().
->where('shared', false)
->get();

foreach ($files as $file) {
// Only delete if this post is the file's sole association.
// posts()->count() is still accurate here because the cascade hasn't run yet.
if ($file->posts()->count() !== 1) {
// File is referenced by other posts — leave it; cascade removes only this pivot row.
continue;
}

$adapter = $this->manager->instantiate($file->upload_method);

if ($adapter->delete($file)) {
$file->delete();
}
// If storage deletion fails we leave the DB record intact — no silent data loss.
}
}
}
Loading