Commit 41d8efe6 authored by Yassine Doghri's avatar Yassine Doghri
Browse files

fix: delete files using file_manager when deleting episode and podcast

- add deleteAll method to file manager
- refactor deletePodcastImageSizes and
deletePersonImagesSizes implementations
parent 7e1a470b
Loading
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -911,9 +911,11 @@ class EpisodeController extends BaseController
            $episodeMediaList[] = $this->episode->cover;
        }

        $mediaModel = new MediaModel();

        //delete episode media records from database
        foreach ($episodeMediaList as $episodeMedia) {
            if ($episodeMedia !== null && ! $episodeMedia->delete()) {
            if ($episodeMedia !== null && ! $mediaModel->delete($episodeMedia->id)) {
                $db->transRollback();
                return redirect()
                    ->back()
+11 −9
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ use Modules\Analytics\Models\AnalyticsPodcastModel;
use Modules\Analytics\Models\AnalyticsWebsiteByBrowserModel;
use Modules\Analytics\Models\AnalyticsWebsiteByEntryPageModel;
use Modules\Analytics\Models\AnalyticsWebsiteByRefererModel;
use Modules\Media\FileManagers\FileManagerInterface;
use Modules\Media\Models\MediaModel;

class PodcastController extends BaseController
@@ -497,8 +498,10 @@ class PodcastController extends BaseController
                $episodeMediaList[] = $podcastEpisode->cover;
            }

            $mediaModel = new MediaModel();

            foreach ($episodeMediaList as $episodeMedia) {
                if ($episodeMedia !== null && ! $episodeMedia->delete()) {
                if ($episodeMedia !== null && ! $mediaModel->delete($episodeMedia->id)) {
                    $db->transRollback();
                    return redirect()
                        ->back()
@@ -538,8 +541,10 @@ class PodcastController extends BaseController
            ];
        }

        $mediaModel = new MediaModel();

        foreach ($podcastMediaList as $podcastMedia) {
            if ($podcastMedia['file'] !== null && ! $podcastMedia['file']->delete()) {
            if ($podcastMedia['file'] !== null && ! $mediaModel->delete($podcastMedia['file']->id)) {
                $db->transRollback();
                return redirect()
                    ->back()
@@ -587,15 +592,12 @@ class PodcastController extends BaseController

        $db->transComplete();

        /** @var FileManagerInterface $fileManager */
        $fileManager = service('file_manager');

        //delete podcast media files and folder
        $folder = 'podcasts/' . $this->podcast->handle;

        $mediaRoot = config('App')
            ->mediaRoot . '/' . $folder;

        helper('filesystem');

        if (! delete_files($mediaRoot) || ! rmdir($mediaRoot)) {
        if (! $fileManager->deleteAll($folder)) {
            return redirect()->route('podcast-list')
                ->with('message', lang('Podcast.messages.deleteSuccess', [
                    'podcast_handle' => $this->podcast->handle,
+23 −27
Original line number Diff line number Diff line
@@ -51,7 +51,7 @@ class FS implements FileManagerInterface
    {
        helper('media');

        return unlink(media_path_absolute($key));
        return @unlink(media_path_absolute($key));
    }

    public function getUrl(string $key): string
@@ -89,47 +89,43 @@ class FS implements FileManagerInterface

    public function deletePodcastImageSizes(string $podcastHandle): bool
    {
        helper('media');

        $allPodcastImagesPaths = [];
        foreach (['jpg', 'jpeg', 'png', 'webp'] as $ext) {
            $images = glob(media_path_absolute("/podcasts/{$podcastHandle}/*_*{$ext}"));

            if (! $images) {
                return false;
            $this->deleteAll("podcasts/{$podcastHandle}", "*_*{$ext}");
        }

            array_push($allPodcastImagesPaths, ...$images);
        return true;
    }

        foreach ($allPodcastImagesPaths as $podcastImagePath) {
            if (is_file($podcastImagePath)) {
                unlink($podcastImagePath);
            }
    public function deletePersonImagesSizes(): bool
    {
        foreach (['jpg', 'jpeg', 'png', 'webp'] as $ext) {
            $this->deleteAll('persons', "*_*{$ext}");
        }

        return true;
    }

    public function deletePersonImagesSizes(): bool
    public function deleteAll(string $prefix, string $pattern = '*'): bool
    {
        helper('media');

        $allPersonsImagesPaths = [];
        foreach (['jpg', 'jpeg', 'png', 'webp'] as $ext) {
            $images = glob(media_path_absolute("/persons/*_*{$ext}"));
        // delete all in folder?
        if ($pattern === '*') {
            helper('filesystem');

            if (! $images) {
                return false;
            return delete_files(media_path_absolute($prefix), true);
        }

            array_push($allPersonsImagesPaths, ...$images);
        }
        $prefix = rtrim($prefix, '/') . '/';

        $imagePaths = glob(media_path_absolute($prefix . $pattern));

        foreach ($allPersonsImagesPaths as $personImagePath) {
            if (is_file($personImagePath)) {
                unlink($personImagePath);
        if (! $imagePaths) {
            return true;
        }

        foreach ($imagePaths as $imagePath) {
            @unlink($imagePath);
        }

        return true;
+2 −0
Original line number Diff line number Diff line
@@ -24,5 +24,7 @@ interface FileManagerInterface

    public function deletePersonImagesSizes(): bool;

    public function deleteAll(string $prefix, string $pattern = '*'): bool;

    public function isHealthy(): bool;
}
+26 −52
Original line number Diff line number Diff line
@@ -88,7 +88,7 @@ class S3 implements FileManagerInterface
        }

        // delete old object
        return $this->delete($this->prefixKey($oldKey));
        return $this->delete($oldKey);
    }

    public function getFileContents(string $key): string
@@ -108,72 +108,46 @@ class S3 implements FileManagerInterface

    public function deletePodcastImageSizes(string $podcastHandle): bool
    {
        $results = $this->s3->getPaginator('ListObjectsV2', [
            'Bucket' => $this->config->s3['bucket'],
            'Prefix' => $this->prefixKey('podcasts/' . $podcastHandle . '/'),
        ]);

        $keys = [];
        foreach ($results as $result) {
            $key = array_map(static function ($object) {
                return $object['Key'];
            }, $result['Contents']);

            $prefixedPodcasts = $this->prefixKey('podcasts');

            array_push(
                $keys,
                ...preg_grep("~^{$prefixedPodcasts}\/{$podcastHandle}\/.*_.*.\.(jpe?g|png|webp)$~", $key)
            );
        foreach (['jpg', 'jpeg', 'png', 'webp'] as $ext) {
            $this->deleteAll('podcasts/' . $podcastHandle, "*_*{$ext}");
        }

        $objectsToDelete = array_map(static function ($key): array {
            return [
                'Key' => $key,
            ];
        }, $keys);

        if ($objectsToDelete === []) {
        return true;
    }

        try {
            $this->s3->deleteObjects([
                'Bucket' => $this->config->s3['bucket'],
                'Delete' => [
                    'Objects' => $objectsToDelete,
                ],
            ]);
        } catch (Exception) {
            return false;
    public function deletePersonImagesSizes(): bool
    {
        foreach (['jpg', 'jpeg', 'png', 'webp'] as $ext) {
            $this->deleteAll('persons', "*_*{$ext}");
        }

        return true;
    }

    public function deletePersonImagesSizes(): bool
    public function deleteAll(string $prefix, ?string $pattern = '*'): bool
    {
        $prefix = rtrim($this->prefixKey($prefix), '/') . '/'; // make sure that there is a trailing slash
        $pattern = $prefix . $pattern;

        $results = $this->s3->getPaginator('ListObjectsV2', [
            'Bucket' => $this->config->s3['bucket'],
            'prefix' => $this->prefixKey('persons/'),
            'prefix' => $prefix,
        ]);

        $keys = [];
        $objectsToDelete = [];
        foreach ($results as $result) {
            $key = array_map(static function ($object) {
                return $object['Key'];
            }, $result['Contents']);

            $prefixedPersons = $this->prefixKey('persons');

            array_push($keys, ...preg_grep("~^{$prefixedPersons}\/.*_.*.\.(jpe?g|png|webp)$~", $key));
            if ($result['Contents'] === null) {
                continue;
            }

        $objectsToDelete = array_map(static function ($key): array {
            return [
                'Key' => $key,
            foreach ($result['Contents'] as $object) {
                if (fnmatch($pattern, $object['Key'])) {
                    $objectsToDelete[] = [
                        'Key' => $object['Key'],
                    ];
        }, $keys);
                }
            }
        }

        if ($objectsToDelete === []) {
            return true;
Loading