Skip to content
Snippets Groups Projects
Commit 89dee41d authored by Yassine Doghri's avatar Yassine Doghri
Browse files

feat: add housekeeping task to run after migrations

add run housekeeping button in general settings page
parent 38899124
No related branches found
No related tags found
No related merge requests found
......@@ -145,6 +145,21 @@ class MediaModel extends Model
return $this->update($media->id, $media);
}
/**
* @return array<mixed>
*/
public function getAllOfType(): array
{
$result = $this->where('type', $this->fileType)
->findAll();
$mediaClass = $this->returnType;
foreach ($result as $key => $media) {
$result[$key] = new $mediaClass($media->toArray(false, true));
}
return $result;
}
public function deleteMedia(object $media): bool
{
$media->deleteFile();
......
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<g>
<path fill="none" d="M0 0h24v24H0z"/>
<path d="M20 20a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-9H1l10.327-9.388a1 1 0 0 1 1.346 0L23 11h-3v9zM8.592 13.808l-.991.572 1 1.733.993-.573a3.5 3.5 0 0 0 1.405.811v1.145h2.002V16.35a3.5 3.5 0 0 0 1.405-.81l.992.572L16.4 14.38l-.991-.572a3.504 3.504 0 0 0 0-1.62l.991-.573-1-1.733-.993.573A3.5 3.5 0 0 0 13 9.645V8.5h-2.002v1.144a3.5 3.5 0 0 0-1.405.811l-.992-.573L7.6 11.616l.991.572a3.504 3.504 0 0 0 0 1.62zm3.408.69a1.5 1.5 0 1 1-.002-3.001 1.5 1.5 0 0 1 .002 3z"/>
</g>
</svg>
......@@ -46,6 +46,12 @@ class Button extends Component
'large' => 'text-base leading-6',
];
$iconSize = [
'small' => 'text-sm',
'base' => 'text-lg',
'large' => 'text-2xl',
];
$basePaddings = [
'small' => 'px-3 py-1',
'base' => 'px-3 py-2',
......@@ -77,14 +83,14 @@ class Button extends Component
if ($this->iconLeft !== '') {
$this->slot = (new Icon([
'glyph' => $this->iconLeft,
'class' => 'mr-2 opacity-75',
'class' => 'mr-2 opacity-75' . ' ' . $iconSize[$this->size],
]))->render() . $this->slot;
}
if ($this->iconRight !== '') {
$this->slot .= (new Icon([
'glyph' => $this->iconRight,
'class' => 'ml-2 opacity-75',
'class' => 'ml-2 opacity-75' . ' ' . $iconSize[$this->size],
]))->render();
}
......
......@@ -40,6 +40,10 @@ $routes->group(
'as' => 'settings-images-regenerate',
'filter' => 'permission:settings-manage',
]);
$routes->post('instance-housekeeping-run', 'SettingsController::runHousekeeping', [
'as' => 'settings-housekeeping-run',
'filter' => 'permission:settings-manage',
]);
$routes->get('theme', 'SettingsController::theme', [
'as' => 'settings-theme',
'filter' => 'permission:settings-manage',
......
......@@ -10,8 +10,12 @@ declare(strict_types=1);
namespace Modules\Admin\Controllers;
use App\Entities\Media\Image;
use App\Models\ActorModel;
use App\Models\MediaModel;
use App\Models\PersonModel;
use App\Models\PodcastModel;
use CodeIgniter\Files\File;
use CodeIgniter\HTTP\RedirectResponse;
use PHP_ICO;
......@@ -156,6 +160,108 @@ class SettingsController extends BaseController
return redirect('settings-general')->with('message', lang('Settings.images.regenerationSuccess'));
}
public function runHousekeeping(): RedirectResponse
{
helper('media');
// Delete all podcast image sizes to recreate them
$allPodcasts = (new PodcastModel())->findAll();
foreach ($allPodcasts as $podcast) {
$podcastImages = glob(
ROOTPATH . 'public/' . config('App')->mediaRoot . "/podcasts/{$podcast->handle}/*_*{jpg,png,webp}",
GLOB_BRACE
);
if ($podcastImages) {
foreach ($podcastImages as $podcastImage) {
if (is_file($podcastImage)) {
unlink($podcastImage);
}
}
}
}
// Delete all person image sizes to recreate them
$personsImages = glob(
ROOTPATH . 'public/' . config('App')->mediaRoot . '/persons/*_*{jpg,png,webp}',
GLOB_BRACE
);
if ($personsImages) {
foreach ($personsImages as $personsImage) {
if (is_file($personsImage)) {
unlink($personsImage);
}
}
}
$allImages = (new MediaModel('image'))->getAllOfType();
foreach ($allImages as $image) {
if (str_starts_with($image->file_path, 'podcasts')) {
if (str_ends_with($image->file_path, 'banner.jpg') || str_ends_with($image->file_path, 'banner.png')) {
$image->sizes = config('Images')
->podcastBannerSizes;
} else {
$image->sizes = config('Images')
->podcastCoverSizes;
}
} elseif (str_starts_with($image->file_path, 'persons')) {
$image->sizes = config('Images')
->personAvatarSizes;
}
$image->setFile(new File(media_path($image->file_path)));
(new MediaModel('image'))->updateMedia($image);
}
$allAudio = (new MediaModel('audio'))->getAllOfType();
foreach ($allAudio as $audio) {
$audio->setFile(new File(media_path($audio->file_path)));
(new MediaModel('audio'))->updateMedia($audio);
}
$allTranscripts = (new MediaModel('transcript'))->getAllOfType();
foreach ($allTranscripts as $transcript) {
$transcript->setFile(new File(media_path($transcript->file_path)));
(new MediaModel('transcript'))->updateMedia($transcript);
}
$allChapters = (new MediaModel('chapters'))->getAllOfType();
foreach ($allChapters as $chapters) {
$chapters->setFile(new File(media_path($chapters->file_path)));
(new MediaModel('chapters'))->updateMedia($chapters);
}
$allVideos = (new MediaModel('video'))->getAllOfType();
foreach ($allVideos as $video) {
$video->setFile(new File(media_path($video->file_path)));
(new MediaModel('video'))->updateMedia($video);
}
// reset avatar and banner image urls for each podcast actor
foreach ($allPodcasts as $podcast) {
$actorModel = new ActorModel();
$actor = $actorModel->getActorById($podcast->actor_id);
if ($actor !== null) {
// update values
$actor->avatar_image_url = $podcast->cover->federation_url;
$actor->avatar_image_mimetype = $podcast->cover->file_mimetype;
$actor->cover_image_url = $podcast->banner->federation_url;
$actor->cover_image_mimetype = $podcast->banner->file_mimetype;
if ($actor->hasChanged()) {
$actorModel->update($actor->id, $actor);
}
}
}
return redirect('settings-general')->with('message', lang('Settings.housekeeping.runSuccess'));
}
public function theme(): string
{
helper('form');
......
......@@ -28,6 +28,12 @@ return [
'regenerate' => 'Regenerate images',
'regenerationSuccess' => 'All images have been regenerated successfully!',
],
'housekeeping' => [
'title' => 'Housekeeping',
'subtitle' => 'Runs various housekeeping tasks, such as rewriting media files metadata (images, audio files, transcripts, chapters, …).',
'run' => 'Run housekeeping',
'runSuccess' => 'Housekeeping has been run successfully!',
],
'theme' => [
'title' => 'Theme',
'accent_section_title' => 'Accent color',
......
......@@ -28,6 +28,12 @@ return [
'regenerate' => 'Regénérer les images',
'regenerationSuccess' => 'Toutes les images ont été regénérés avec succès !',
],
'housekeeping' => [
'title' => 'Ménage',
'subtitle' => 'Exécute un nombre de tâches de nettoyage, comme la réécriture de métadonnées des fichiers media (images, fichiers audio, transcript, chapitres, …).',
'run' => 'Faire le ménage',
'runSuccess' => 'Le ménage a été effectué avec succès !',
],
'theme' => [
'title' => 'Thème',
'accent_section_title' => 'Couleur d’accentuation',
......
......@@ -69,6 +69,20 @@
</Forms.Section>
</form>
<form action="<?= route_to('settings-housekeeping-run') ?>" method="POST" class="flex flex-col max-w-xl gap-y-4">
<?= csrf_field() ?>
<Forms.Section
title="<?= lang('Settings.housekeeping.title') ?>"
subtitle="<?= lang('Settings.housekeeping.subtitle') ?>" >
<Button variant="primary" type="submit" iconLeft="home-gear"><?= lang('Settings.housekeeping.run') ?></Button>
</Forms.Section>
</form>
</div>
<?= $this->endSection() ?>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment