From 0a66de3e6c17d4ac94ee8e13bd00ceaf64b1303e Mon Sep 17 00:00:00 2001 From: Yassine Doghri Date: Tue, 25 May 2021 18:00:09 +0000 Subject: [PATCH] fix: set cache expiration to next note publish to show note on publication date fix episode, podcast and persons forms + episode scheduling --- app/Config/Events.php | 22 +++++++++++++++++ app/Controllers/Admin/EpisodeController.php | 15 ++++++++---- .../Admin/EpisodePersonController.php | 6 ++--- app/Controllers/Admin/PodcastController.php | 4 ++-- app/Controllers/PodcastController.php | 9 ++++++- app/Entities/Episode.php | 3 ++- app/Entities/Person.php | 2 +- app/Language/en/Person.php | 22 ++++++++--------- .../ActivityPub/Models/NoteModel.php | 24 ++++++++++++++++++- app/Libraries/Analytics/AnalyticsTrait.php | 2 +- app/Models/EpisodeModel.php | 6 ++--- app/Models/PersonModel.php | 18 ++++++++++++-- app/Views/admin/episode/persons.php | 22 ++++++++--------- app/Views/admin/podcast/persons.php | 6 ++--- 14 files changed, 117 insertions(+), 44 deletions(-) diff --git a/app/Config/Events.php b/app/Config/Events.php index 59cc1e6c..dc9fe3a3 100644 --- a/app/Config/Events.php +++ b/app/Config/Events.php @@ -89,6 +89,8 @@ Events::on('on_note_add', function (Note $note): void { // same for other events below cache() ->deleteMatching("page_podcast#{$note->actor->podcast->id}*"); + cache() + ->deleteMatching("podcast#{$note->actor->podcast->id}*"); }); Events::on('on_note_remove', function (Note $note): void { @@ -108,6 +110,8 @@ Events::on('on_note_remove', function (Note $note): void { cache() ->deleteMatching("page_podcast#{$note->actor->podcast->id}*"); + cache() + ->deleteMatching("podcast#{$note->actor->podcast->id}*"); cache() ->deleteMatching("page_note#{$note->id}*"); }); @@ -125,6 +129,8 @@ Events::on('on_note_reblog', function (Actor $actor, Note $note): void { cache() ->deleteMatching("page_podcast#{$note->actor->podcast->id}*"); + cache() + ->deleteMatching("podcast#{$note->actor->podcast->id}*"); cache() ->deleteMatching("page_note#{$note->id}*"); @@ -147,6 +153,8 @@ Events::on('on_note_undo_reblog', function (Note $reblogNote): void { cache() ->deleteMatching("page_podcast#{$note->actor->podcast->id}*"); + cache() + ->deleteMatching("podcast#{$note->actor->podcast->id}*"); cache() ->deleteMatching("page_note#{$note->id}*"); @@ -169,6 +177,8 @@ Events::on('on_reply_remove', function (Note $reply): void { cache() ->deleteMatching("page_podcast#{$note->actor->podcast->id}*"); + cache() + ->deleteMatching("podcast#{$note->actor->podcast->id}*"); cache() ->deleteMatching("page_note#{$note->id}*"); }); @@ -182,6 +192,8 @@ Events::on('on_note_favourite', function (Actor $actor, Note $note): void { cache() ->deleteMatching("page_podcast#{$actor->podcast->id}*"); + cache() + ->deleteMatching("podcast#{$actor->podcast->id}*"); cache() ->deleteMatching("page_note#{$note->id}*"); @@ -199,6 +211,8 @@ Events::on('on_note_undo_favourite', function (Actor $actor, Note $note): void { cache() ->deleteMatching("page_podcast#{$actor->podcast->id}*"); + cache() + ->deleteMatching("podcast#{$actor->podcast->id}*"); cache() ->deleteMatching("page_note#{$note->id}*"); @@ -209,24 +223,32 @@ Events::on('on_note_undo_favourite', function (Actor $actor, Note $note): void { Events::on('on_block_actor', function (int $actorId): void { cache()->deleteMatching('page_podcast*'); + cache() + ->deleteMatching('podcast*'); cache() ->deleteMatching('page_note*'); }); Events::on('on_unblock_actor', function (int $actorId): void { cache()->deleteMatching('page_podcast*'); + cache() + ->deleteMatching('podcast*'); cache() ->deleteMatching('page_note*'); }); Events::on('on_block_domain', function (string $domainName): void { cache()->deleteMatching('page_podcast*'); + cache() + ->deleteMatching('podcast*'); cache() ->deleteMatching('page_note*'); }); Events::on('on_unblock_domain', function (string $domainName): void { cache()->deleteMatching('page_podcast*'); + cache() + ->deleteMatching('podcast*'); cache() ->deleteMatching('page_note*'); }); diff --git a/app/Controllers/Admin/EpisodeController.php b/app/Controllers/Admin/EpisodeController.php index 6d1b99fb..b7c50042 100644 --- a/app/Controllers/Admin/EpisodeController.php +++ b/app/Controllers/Admin/EpisodeController.php @@ -9,6 +9,7 @@ namespace App\Controllers\Admin; use App\Entities\Episode; +use App\Entities\Image; use App\Entities\Location; use App\Entities\Note; use App\Entities\Podcast; @@ -118,6 +119,12 @@ class EpisodeController extends BaseController ->with('errors', $this->validator->getErrors()); } + $image = null; + $imageFile = $this->request->getFile('image'); + if ($imageFile !== null && $imageFile->isValid()) { + $image = new Image($imageFile); + } + $newEpisode = new Episode([ 'podcast_id' => $this->podcast->id, 'title' => $this->request->getPost('title'), @@ -125,7 +132,7 @@ class EpisodeController extends BaseController 'guid' => '', 'audio_file' => $this->request->getFile('audio_file'), 'description_markdown' => $this->request->getPost('description'), - 'image' => $this->request->getFile('image'), + 'image' => $image, 'location' => new Location($this->request->getPost('location_name'),), 'transcript' => $this->request->getFile('transcript'), 'chapters' => $this->request->getFile('chapters'), @@ -253,9 +260,9 @@ class EpisodeController extends BaseController $this->episode->audio_file = $audioFile; } - $image = $this->request->getFile('image'); - if ($image !== null && $image->isValid()) { - $this->episode->image = $image; + $imageFile = $this->request->getFile('image'); + if ($imageFile !== null && $imageFile->isValid()) { + $this->episode->image = new Image($imageFile); } $transcriptChoice = $this->request->getPost('transcript-choice'); diff --git a/app/Controllers/Admin/EpisodePersonController.php b/app/Controllers/Admin/EpisodePersonController.php index 00284564..4257bef2 100644 --- a/app/Controllers/Admin/EpisodePersonController.php +++ b/app/Controllers/Admin/EpisodePersonController.php @@ -66,7 +66,7 @@ class EpisodePersonController extends BaseController public function attemptAdd(): RedirectResponse { $rules = [ - 'person' => 'required', + 'persons' => 'required', ]; if (! $this->validate($rules)) { @@ -79,8 +79,8 @@ class EpisodePersonController extends BaseController (new PersonModel())->addEpisodePersons( $this->podcast->id, $this->episode->id, - $this->request->getPost('person'), - $this->request->getPost('person_group_role'), + $this->request->getPost('persons'), + $this->request->getPost('roles') ?? [], ); return redirect()->back(); diff --git a/app/Controllers/Admin/PodcastController.php b/app/Controllers/Admin/PodcastController.php index f48875fa..47717682 100644 --- a/app/Controllers/Admin/PodcastController.php +++ b/app/Controllers/Admin/PodcastController.php @@ -230,7 +230,7 @@ class PodcastController extends BaseController // set Podcast categories (new CategoryModel())->setPodcastCategories( (int) $newPodcastId, - $this->request->getPost('other_categories'), + $this->request->getPost('other_categories') ?? [], ); // set interact as the newly created podcast actor @@ -320,7 +320,7 @@ class PodcastController extends BaseController // set Podcast categories (new CategoryModel())->setPodcastCategories( $this->podcast->id, - $this->request->getPost('other_categories'), + $this->request->getPost('other_categories') ?? [], ); $db->transComplete(); diff --git a/app/Controllers/PodcastController.php b/app/Controllers/PodcastController.php index 680cb5fc..b9b1da35 100644 --- a/app/Controllers/PodcastController.php +++ b/app/Controllers/PodcastController.php @@ -67,8 +67,15 @@ class PodcastController extends BaseController helper('form'); return view('podcast/activity_authenticated', $data); } + + $secondsToNextUnpublishedEpisode = (new EpisodeModel())->getSecondsToNextUnpublishedEpisode( + $this->podcast->id, + ); + return view('podcast/activity', $data, [ - 'cache' => DECADE, + 'cache' => $secondsToNextUnpublishedEpisode + ? $secondsToNextUnpublishedEpisode + : DECADE, 'cache_name' => $cacheName, ]); } diff --git a/app/Entities/Episode.php b/app/Entities/Episode.php index 22bca73c..b54c4376 100644 --- a/app/Entities/Episode.php +++ b/app/Entities/Episode.php @@ -192,7 +192,8 @@ class Episode extends Entity return new Image(null, $imagePath, $this->attributes['image_mimetype'],); } - return $this->podcast->image; + return $this->getPodcast() + ->image; } /** diff --git a/app/Entities/Person.php b/app/Entities/Person.php index c9f9f568..3e298f4d 100644 --- a/app/Entities/Person.php +++ b/app/Entities/Person.php @@ -87,7 +87,7 @@ class Person extends Entity $this->roles = (new PersonModel())->getPersonRoles( $this->id, $this->attributes['podcast_id'], - $this->episode_id + $this->attributes['episode_id'] ?? null ); } diff --git a/app/Language/en/Person.php b/app/Language/en/Person.php index 3d504b2a..1c7ce78e 100644 --- a/app/Language/en/Person.php +++ b/app/Language/en/Person.php @@ -36,12 +36,12 @@ return [ 'manage_section_subtitle' => 'Remove persons from this podcast', 'add_section_title' => 'Add persons to this podcast', 'add_section_subtitle' => 'You may pick several persons and roles.', - 'person' => 'Persons', - 'person_hint' => + 'persons' => 'Persons', + 'persons_hint' => 'You may select one or several persons with the same roles. You need to create the persons first.', - 'group_role' => 'Groups and roles', - 'group_role_hint' => - 'You may select none, one or several groups and roles for a person.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', 'submit_add' => 'Add person(s)', 'remove' => 'Remove', ], @@ -50,13 +50,13 @@ return [ 'manage_section_title' => 'Management', 'manage_section_subtitle' => 'Remove persons from this episode', 'add_section_title' => 'Add persons to this episode', - 'add_section_subtitle' => 'You may pick several persons and roles', - 'person' => 'Persons', - 'person_hint' => + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => 'You may select one or several persons with the same roles. You need to create the persons first.', - 'group_role' => 'Groups and roles', - 'group_role_hint' => - 'You may select none, one or several groups and roles for a person.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', 'submit_add' => 'Add person(s)', 'remove' => 'Remove', ], diff --git a/app/Libraries/ActivityPub/Models/NoteModel.php b/app/Libraries/ActivityPub/Models/NoteModel.php index 5d9b6d2a..8eca3d44 100644 --- a/app/Libraries/ActivityPub/Models/NoteModel.php +++ b/app/Libraries/ActivityPub/Models/NoteModel.php @@ -138,13 +138,35 @@ class NoteModel extends UuidModel ->orderBy('published_at', 'DESC') ->findAll(); + $secondsToNextUnpublishedNote = $this->getSecondsToNextUnpublishedNote($actorId,); + cache() - ->save($cacheName, $found, DECADE); + ->save($cacheName, $found, $secondsToNextUnpublishedNote ? $secondsToNextUnpublishedNote : DECADE,); } return $found; } + /** + * Returns the timestamp difference in seconds between the next note to publish and the current timestamp. Returns + * false if there's no note to publish + */ + public function getSecondsToNextUnpublishedNote(int $actorId): int | false + { + $result = $this->select('TIMESTAMPDIFF(SECOND, NOW(), `published_at`) as timestamp_diff',) + ->where([ + 'actor_id' => $actorId, + ]) + ->where('`published_at` > NOW()', null, false) + ->orderBy('published_at', 'asc') + ->get() + ->getResultArray(); + + return count($result) !== 0 + ? (int) $result[0]['timestamp_diff'] + : false; + } + /** * Retrieves all published replies for a given note. By default, it does not get replies from blocked actors. * diff --git a/app/Libraries/Analytics/AnalyticsTrait.php b/app/Libraries/Analytics/AnalyticsTrait.php index cef20218..d2561ffa 100644 --- a/app/Libraries/Analytics/AnalyticsTrait.php +++ b/app/Libraries/Analytics/AnalyticsTrait.php @@ -34,7 +34,7 @@ trait AnalyticsTrait ? '- Direct -' : parse_url($referer, PHP_URL_HOST); parse_str(parse_url($referer, PHP_URL_QUERY), $queries); - $keywords = array_key_exists('q', $queries) ? $queries['q'] : null; + $keywords = $queries['q'] ?? null; $procedureName = $db->prefixTable('analytics_website'); $db->query("call {$procedureName}(?,?,?,?,?,?)", [ diff --git a/app/Models/EpisodeModel.php b/app/Models/EpisodeModel.php index c6a231fe..8b0a2828 100644 --- a/app/Models/EpisodeModel.php +++ b/app/Models/EpisodeModel.php @@ -316,12 +316,12 @@ class EpisodeModel extends Model cache() ->delete("podcast_episode#{$episode->id}"); cache() - ->deleteMatching("podcast#{$episode->podcast_id}_episode#{$episode->id}*",); + ->deleteMatching("podcast#{$episode->podcast_id}_episode#{$episode->id}*"); cache() - ->delete("podcast#{$episode->podcast_id}_episode-{$episode->slug}",); + ->delete("podcast#{$episode->podcast_id}_episode-{$episode->slug}"); cache() - ->deleteMatching("page_podcast#{$episode->podcast_id}_activity*",); + ->deleteMatching("page_podcast#{$episode->podcast_id}_activity*"); cache() ->deleteMatching("page_podcast#{$episode->podcast_id}_episode#{$episode->id}_*",); cache() diff --git a/app/Models/PersonModel.php b/app/Models/PersonModel.php index 293c122e..3101acda 100644 --- a/app/Models/PersonModel.php +++ b/app/Models/PersonModel.php @@ -107,7 +107,7 @@ class PersonModel extends Model */ public function getPersonRoles(int $personId, int $podcastId, ?int $episodeId): array { - if ($episodeId) { + if ($episodeId !== null) { $cacheName = "podcast#{$podcastId}_episode#{$episodeId}_person#{$personId}_roles"; if (! ($found = cache($cacheName))) { @@ -212,7 +212,9 @@ class PersonModel extends Model $cacheName = "podcast#{$podcastId}_episode#{$episodeId}_persons"; if (! ($found = cache($cacheName))) { $found = $this - ->select('persons.*, episodes_persons.podcast_id, episodes_persons.episode_id') + ->select( + 'persons.*, episodes_persons.podcast_id as podcast_id, episodes_persons.episode_id as episode_id' + ) ->distinct() ->join('episodes_persons', 'persons.id = episodes_persons.person_id') ->where('episodes_persons.episode_id', $episodeId) @@ -321,6 +323,7 @@ class PersonModel extends Model } return $this->db->table('podcasts_persons') + ->ignore(true) ->insertBatch($data); } @@ -331,6 +334,10 @@ class PersonModel extends Model */ public function removePersonFromPodcast(int $podcastId, int $personId): string | bool { + cache()->deleteMatching("podcast#{$podcastId}_person#{$personId}*"); + cache() + ->delete("podcast#{$podcastId}_persons"); + return $this->db->table('podcasts_persons') ->delete([ 'podcast_id' => $podcastId, @@ -353,6 +360,8 @@ class PersonModel extends Model array $groupsRoles ): bool | int { if ($personIds !== []) { + cache() + ->delete("podcast#{$podcastId}_episode#{$episodeId}_persons"); (new EpisodeModel())->clearCache([ 'id' => $episodeId, ]); @@ -379,6 +388,7 @@ class PersonModel extends Model } } return $this->db->table('episodes_persons') + ->ignore(true) ->insertBatch($data); } return 0; @@ -386,6 +396,10 @@ class PersonModel extends Model public function removePersonFromEpisode(int $podcastId, int $episodeId, int $personId): bool | string { + cache()->deleteMatching("podcast#{$podcastId}_episode#{$episodeId}_person#{$personId}*"); + cache() + ->delete("podcast#{$podcastId}_episode#{$episodeId}_persons"); + return $this->db->table('episodes_persons') ->delete([ 'podcast_id' => $podcastId, diff --git a/app/Views/admin/episode/persons.php b/app/Views/admin/episode/persons.php index 08d681de..293129f5 100644 --- a/app/Views/admin/episode/persons.php +++ b/app/Views/admin/episode/persons.php @@ -96,29 +96,29 @@ ) ?> - 'person', + 'persons', 'class' => 'form-select mb-4', 'required' => 'required', ]) ?> 'person_group_role', 'class' => 'form-select mb-4'], + old('roles', []), + ['id' => 'roles', 'class' => 'form-select mb-4'], ) ?> diff --git a/app/Views/admin/podcast/persons.php b/app/Views/admin/podcast/persons.php index 8edb6876..506cedfe 100644 --- a/app/Views/admin/podcast/persons.php +++ b/app/Views/admin/podcast/persons.php @@ -94,10 +94,10 @@ ) ?> 'persons',