fix: set cache expiration to next note publish to show note on publication date

fix episode, podcast and persons forms + episode scheduling
This commit is contained in:
Yassine Doghri 2021-05-25 18:00:09 +00:00
parent fbc0967caa
commit 0a66de3e6c
No known key found for this signature in database
GPG Key ID: 3E7F89498B960C9F
14 changed files with 117 additions and 44 deletions

View File

@ -89,6 +89,8 @@ Events::on('on_note_add', function (Note $note): void {
// same for other events below // same for other events below
cache() cache()
->deleteMatching("page_podcast#{$note->actor->podcast->id}*"); ->deleteMatching("page_podcast#{$note->actor->podcast->id}*");
cache()
->deleteMatching("podcast#{$note->actor->podcast->id}*");
}); });
Events::on('on_note_remove', function (Note $note): void { Events::on('on_note_remove', function (Note $note): void {
@ -108,6 +110,8 @@ Events::on('on_note_remove', function (Note $note): void {
cache() cache()
->deleteMatching("page_podcast#{$note->actor->podcast->id}*"); ->deleteMatching("page_podcast#{$note->actor->podcast->id}*");
cache()
->deleteMatching("podcast#{$note->actor->podcast->id}*");
cache() cache()
->deleteMatching("page_note#{$note->id}*"); ->deleteMatching("page_note#{$note->id}*");
}); });
@ -125,6 +129,8 @@ Events::on('on_note_reblog', function (Actor $actor, Note $note): void {
cache() cache()
->deleteMatching("page_podcast#{$note->actor->podcast->id}*"); ->deleteMatching("page_podcast#{$note->actor->podcast->id}*");
cache()
->deleteMatching("podcast#{$note->actor->podcast->id}*");
cache() cache()
->deleteMatching("page_note#{$note->id}*"); ->deleteMatching("page_note#{$note->id}*");
@ -147,6 +153,8 @@ Events::on('on_note_undo_reblog', function (Note $reblogNote): void {
cache() cache()
->deleteMatching("page_podcast#{$note->actor->podcast->id}*"); ->deleteMatching("page_podcast#{$note->actor->podcast->id}*");
cache()
->deleteMatching("podcast#{$note->actor->podcast->id}*");
cache() cache()
->deleteMatching("page_note#{$note->id}*"); ->deleteMatching("page_note#{$note->id}*");
@ -169,6 +177,8 @@ Events::on('on_reply_remove', function (Note $reply): void {
cache() cache()
->deleteMatching("page_podcast#{$note->actor->podcast->id}*"); ->deleteMatching("page_podcast#{$note->actor->podcast->id}*");
cache()
->deleteMatching("podcast#{$note->actor->podcast->id}*");
cache() cache()
->deleteMatching("page_note#{$note->id}*"); ->deleteMatching("page_note#{$note->id}*");
}); });
@ -182,6 +192,8 @@ Events::on('on_note_favourite', function (Actor $actor, Note $note): void {
cache() cache()
->deleteMatching("page_podcast#{$actor->podcast->id}*"); ->deleteMatching("page_podcast#{$actor->podcast->id}*");
cache()
->deleteMatching("podcast#{$actor->podcast->id}*");
cache() cache()
->deleteMatching("page_note#{$note->id}*"); ->deleteMatching("page_note#{$note->id}*");
@ -199,6 +211,8 @@ Events::on('on_note_undo_favourite', function (Actor $actor, Note $note): void {
cache() cache()
->deleteMatching("page_podcast#{$actor->podcast->id}*"); ->deleteMatching("page_podcast#{$actor->podcast->id}*");
cache()
->deleteMatching("podcast#{$actor->podcast->id}*");
cache() cache()
->deleteMatching("page_note#{$note->id}*"); ->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 { Events::on('on_block_actor', function (int $actorId): void {
cache()->deleteMatching('page_podcast*'); cache()->deleteMatching('page_podcast*');
cache()
->deleteMatching('podcast*');
cache() cache()
->deleteMatching('page_note*'); ->deleteMatching('page_note*');
}); });
Events::on('on_unblock_actor', function (int $actorId): void { Events::on('on_unblock_actor', function (int $actorId): void {
cache()->deleteMatching('page_podcast*'); cache()->deleteMatching('page_podcast*');
cache()
->deleteMatching('podcast*');
cache() cache()
->deleteMatching('page_note*'); ->deleteMatching('page_note*');
}); });
Events::on('on_block_domain', function (string $domainName): void { Events::on('on_block_domain', function (string $domainName): void {
cache()->deleteMatching('page_podcast*'); cache()->deleteMatching('page_podcast*');
cache()
->deleteMatching('podcast*');
cache() cache()
->deleteMatching('page_note*'); ->deleteMatching('page_note*');
}); });
Events::on('on_unblock_domain', function (string $domainName): void { Events::on('on_unblock_domain', function (string $domainName): void {
cache()->deleteMatching('page_podcast*'); cache()->deleteMatching('page_podcast*');
cache()
->deleteMatching('podcast*');
cache() cache()
->deleteMatching('page_note*'); ->deleteMatching('page_note*');
}); });

View File

@ -9,6 +9,7 @@
namespace App\Controllers\Admin; namespace App\Controllers\Admin;
use App\Entities\Episode; use App\Entities\Episode;
use App\Entities\Image;
use App\Entities\Location; use App\Entities\Location;
use App\Entities\Note; use App\Entities\Note;
use App\Entities\Podcast; use App\Entities\Podcast;
@ -118,6 +119,12 @@ class EpisodeController extends BaseController
->with('errors', $this->validator->getErrors()); ->with('errors', $this->validator->getErrors());
} }
$image = null;
$imageFile = $this->request->getFile('image');
if ($imageFile !== null && $imageFile->isValid()) {
$image = new Image($imageFile);
}
$newEpisode = new Episode([ $newEpisode = new Episode([
'podcast_id' => $this->podcast->id, 'podcast_id' => $this->podcast->id,
'title' => $this->request->getPost('title'), 'title' => $this->request->getPost('title'),
@ -125,7 +132,7 @@ class EpisodeController extends BaseController
'guid' => '', 'guid' => '',
'audio_file' => $this->request->getFile('audio_file'), 'audio_file' => $this->request->getFile('audio_file'),
'description_markdown' => $this->request->getPost('description'), 'description_markdown' => $this->request->getPost('description'),
'image' => $this->request->getFile('image'), 'image' => $image,
'location' => new Location($this->request->getPost('location_name'),), 'location' => new Location($this->request->getPost('location_name'),),
'transcript' => $this->request->getFile('transcript'), 'transcript' => $this->request->getFile('transcript'),
'chapters' => $this->request->getFile('chapters'), 'chapters' => $this->request->getFile('chapters'),
@ -253,9 +260,9 @@ class EpisodeController extends BaseController
$this->episode->audio_file = $audioFile; $this->episode->audio_file = $audioFile;
} }
$image = $this->request->getFile('image'); $imageFile = $this->request->getFile('image');
if ($image !== null && $image->isValid()) { if ($imageFile !== null && $imageFile->isValid()) {
$this->episode->image = $image; $this->episode->image = new Image($imageFile);
} }
$transcriptChoice = $this->request->getPost('transcript-choice'); $transcriptChoice = $this->request->getPost('transcript-choice');

View File

@ -66,7 +66,7 @@ class EpisodePersonController extends BaseController
public function attemptAdd(): RedirectResponse public function attemptAdd(): RedirectResponse
{ {
$rules = [ $rules = [
'person' => 'required', 'persons' => 'required',
]; ];
if (! $this->validate($rules)) { if (! $this->validate($rules)) {
@ -79,8 +79,8 @@ class EpisodePersonController extends BaseController
(new PersonModel())->addEpisodePersons( (new PersonModel())->addEpisodePersons(
$this->podcast->id, $this->podcast->id,
$this->episode->id, $this->episode->id,
$this->request->getPost('person'), $this->request->getPost('persons'),
$this->request->getPost('person_group_role'), $this->request->getPost('roles') ?? [],
); );
return redirect()->back(); return redirect()->back();

View File

@ -230,7 +230,7 @@ class PodcastController extends BaseController
// set Podcast categories // set Podcast categories
(new CategoryModel())->setPodcastCategories( (new CategoryModel())->setPodcastCategories(
(int) $newPodcastId, (int) $newPodcastId,
$this->request->getPost('other_categories'), $this->request->getPost('other_categories') ?? [],
); );
// set interact as the newly created podcast actor // set interact as the newly created podcast actor
@ -320,7 +320,7 @@ class PodcastController extends BaseController
// set Podcast categories // set Podcast categories
(new CategoryModel())->setPodcastCategories( (new CategoryModel())->setPodcastCategories(
$this->podcast->id, $this->podcast->id,
$this->request->getPost('other_categories'), $this->request->getPost('other_categories') ?? [],
); );
$db->transComplete(); $db->transComplete();

View File

@ -67,8 +67,15 @@ class PodcastController extends BaseController
helper('form'); helper('form');
return view('podcast/activity_authenticated', $data); return view('podcast/activity_authenticated', $data);
} }
$secondsToNextUnpublishedEpisode = (new EpisodeModel())->getSecondsToNextUnpublishedEpisode(
$this->podcast->id,
);
return view('podcast/activity', $data, [ return view('podcast/activity', $data, [
'cache' => DECADE, 'cache' => $secondsToNextUnpublishedEpisode
? $secondsToNextUnpublishedEpisode
: DECADE,
'cache_name' => $cacheName, 'cache_name' => $cacheName,
]); ]);
} }

View File

@ -192,7 +192,8 @@ class Episode extends Entity
return new Image(null, $imagePath, $this->attributes['image_mimetype'],); return new Image(null, $imagePath, $this->attributes['image_mimetype'],);
} }
return $this->podcast->image; return $this->getPodcast()
->image;
} }
/** /**

View File

@ -87,7 +87,7 @@ class Person extends Entity
$this->roles = (new PersonModel())->getPersonRoles( $this->roles = (new PersonModel())->getPersonRoles(
$this->id, $this->id,
$this->attributes['podcast_id'], $this->attributes['podcast_id'],
$this->episode_id $this->attributes['episode_id'] ?? null
); );
} }

View File

@ -36,12 +36,12 @@ return [
'manage_section_subtitle' => 'Remove persons from this podcast', 'manage_section_subtitle' => 'Remove persons from this podcast',
'add_section_title' => 'Add persons to this podcast', 'add_section_title' => 'Add persons to this podcast',
'add_section_subtitle' => 'You may pick several persons and roles.', 'add_section_subtitle' => 'You may pick several persons and roles.',
'person' => 'Persons', 'persons' => 'Persons',
'person_hint' => 'persons_hint' =>
'You may select one or several persons with the same roles. You need to create the persons first.', 'You may select one or several persons with the same roles. You need to create the persons first.',
'group_role' => 'Groups and roles', 'roles' => 'Roles',
'group_role_hint' => 'roles_hint' =>
'You may select none, one or several groups and roles for a person.', 'You may select none, one or several roles for a person.',
'submit_add' => 'Add person(s)', 'submit_add' => 'Add person(s)',
'remove' => 'Remove', 'remove' => 'Remove',
], ],
@ -50,13 +50,13 @@ return [
'manage_section_title' => 'Management', 'manage_section_title' => 'Management',
'manage_section_subtitle' => 'Remove persons from this episode', 'manage_section_subtitle' => 'Remove persons from this episode',
'add_section_title' => 'Add persons to this episode', 'add_section_title' => 'Add persons to this episode',
'add_section_subtitle' => 'You may pick several persons and roles', 'add_section_subtitle' => 'You may pick several persons and roles.',
'person' => 'Persons', 'persons' => 'Persons',
'person_hint' => 'persons_hint' =>
'You may select one or several persons with the same roles. You need to create the persons first.', 'You may select one or several persons with the same roles. You need to create the persons first.',
'group_role' => 'Groups and roles', 'roles' => 'Roles',
'group_role_hint' => 'roles_hint' =>
'You may select none, one or several groups and roles for a person.', 'You may select none, one or several roles for a person.',
'submit_add' => 'Add person(s)', 'submit_add' => 'Add person(s)',
'remove' => 'Remove', 'remove' => 'Remove',
], ],

View File

@ -138,13 +138,35 @@ class NoteModel extends UuidModel
->orderBy('published_at', 'DESC') ->orderBy('published_at', 'DESC')
->findAll(); ->findAll();
$secondsToNextUnpublishedNote = $this->getSecondsToNextUnpublishedNote($actorId,);
cache() cache()
->save($cacheName, $found, DECADE); ->save($cacheName, $found, $secondsToNextUnpublishedNote ? $secondsToNextUnpublishedNote : DECADE,);
} }
return $found; 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. * Retrieves all published replies for a given note. By default, it does not get replies from blocked actors.
* *

View File

@ -34,7 +34,7 @@ trait AnalyticsTrait
? '- Direct -' ? '- Direct -'
: parse_url($referer, PHP_URL_HOST); : parse_url($referer, PHP_URL_HOST);
parse_str(parse_url($referer, PHP_URL_QUERY), $queries); 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'); $procedureName = $db->prefixTable('analytics_website');
$db->query("call {$procedureName}(?,?,?,?,?,?)", [ $db->query("call {$procedureName}(?,?,?,?,?,?)", [

View File

@ -316,12 +316,12 @@ class EpisodeModel extends Model
cache() cache()
->delete("podcast_episode#{$episode->id}"); ->delete("podcast_episode#{$episode->id}");
cache() cache()
->deleteMatching("podcast#{$episode->podcast_id}_episode#{$episode->id}*",); ->deleteMatching("podcast#{$episode->podcast_id}_episode#{$episode->id}*");
cache() cache()
->delete("podcast#{$episode->podcast_id}_episode-{$episode->slug}",); ->delete("podcast#{$episode->podcast_id}_episode-{$episode->slug}");
cache() cache()
->deleteMatching("page_podcast#{$episode->podcast_id}_activity*",); ->deleteMatching("page_podcast#{$episode->podcast_id}_activity*");
cache() cache()
->deleteMatching("page_podcast#{$episode->podcast_id}_episode#{$episode->id}_*",); ->deleteMatching("page_podcast#{$episode->podcast_id}_episode#{$episode->id}_*",);
cache() cache()

View File

@ -107,7 +107,7 @@ class PersonModel extends Model
*/ */
public function getPersonRoles(int $personId, int $podcastId, ?int $episodeId): array public function getPersonRoles(int $personId, int $podcastId, ?int $episodeId): array
{ {
if ($episodeId) { if ($episodeId !== null) {
$cacheName = "podcast#{$podcastId}_episode#{$episodeId}_person#{$personId}_roles"; $cacheName = "podcast#{$podcastId}_episode#{$episodeId}_person#{$personId}_roles";
if (! ($found = cache($cacheName))) { if (! ($found = cache($cacheName))) {
@ -212,7 +212,9 @@ class PersonModel extends Model
$cacheName = "podcast#{$podcastId}_episode#{$episodeId}_persons"; $cacheName = "podcast#{$podcastId}_episode#{$episodeId}_persons";
if (! ($found = cache($cacheName))) { if (! ($found = cache($cacheName))) {
$found = $this $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() ->distinct()
->join('episodes_persons', 'persons.id = episodes_persons.person_id') ->join('episodes_persons', 'persons.id = episodes_persons.person_id')
->where('episodes_persons.episode_id', $episodeId) ->where('episodes_persons.episode_id', $episodeId)
@ -321,6 +323,7 @@ class PersonModel extends Model
} }
return $this->db->table('podcasts_persons') return $this->db->table('podcasts_persons')
->ignore(true)
->insertBatch($data); ->insertBatch($data);
} }
@ -331,6 +334,10 @@ class PersonModel extends Model
*/ */
public function removePersonFromPodcast(int $podcastId, int $personId): string | bool 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') return $this->db->table('podcasts_persons')
->delete([ ->delete([
'podcast_id' => $podcastId, 'podcast_id' => $podcastId,
@ -353,6 +360,8 @@ class PersonModel extends Model
array $groupsRoles array $groupsRoles
): bool | int { ): bool | int {
if ($personIds !== []) { if ($personIds !== []) {
cache()
->delete("podcast#{$podcastId}_episode#{$episodeId}_persons");
(new EpisodeModel())->clearCache([ (new EpisodeModel())->clearCache([
'id' => $episodeId, 'id' => $episodeId,
]); ]);
@ -379,6 +388,7 @@ class PersonModel extends Model
} }
} }
return $this->db->table('episodes_persons') return $this->db->table('episodes_persons')
->ignore(true)
->insertBatch($data); ->insertBatch($data);
} }
return 0; return 0;
@ -386,6 +396,10 @@ class PersonModel extends Model
public function removePersonFromEpisode(int $podcastId, int $episodeId, int $personId): bool | string 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') return $this->db->table('episodes_persons')
->delete([ ->delete([
'podcast_id' => $podcastId, 'podcast_id' => $podcastId,

View File

@ -96,29 +96,29 @@
) ?> ) ?>
<?= form_label( <?= form_label(
lang('Person.episode_form.person'), lang('Person.episode_form.persons'),
'person', 'persons',
[], [],
lang('Person.episode_form.person_hint'), lang('Person.episode_form.persons_hint'),
) ?> ) ?>
<?= form_multiselect('person[]', $personOptions, old('person', []), [ <?= form_multiselect('persons[]', $personOptions, old('persons', []), [
'id' => 'person', 'id' => 'persons',
'class' => 'form-select mb-4', 'class' => 'form-select mb-4',
'required' => 'required', 'required' => 'required',
]) ?> ]) ?>
<?= form_label( <?= form_label(
lang('Person.episode_form.group_role'), lang('Person.episode_form.roles'),
'group_role', 'roles',
[], [],
lang('Person.episode_form.group_role_hint'), lang('Person.episode_form.roles_hint'),
true, true,
) ?> ) ?>
<?= form_multiselect( <?= form_multiselect(
'person_group_role[]', 'roles[]',
$taxonomyOptions, $taxonomyOptions,
old('person_group_role', []), old('roles', []),
['id' => 'person_group_role', 'class' => 'form-select mb-4'], ['id' => 'roles', 'class' => 'form-select mb-4'],
) ?> ) ?>

View File

@ -94,10 +94,10 @@
) ?> ) ?>
<?= form_label( <?= form_label(
lang('Person.podcast_form.person'), lang('Person.podcast_form.persons'),
'person', 'persons',
[], [],
lang('Person.podcast_form.person_hint'), lang('Person.podcast_form.persons_hint'),
) ?> ) ?>
<?= form_multiselect('persons[]', $personOptions, old('persons', []), [ <?= form_multiselect('persons[]', $personOptions, old('persons', []), [
'id' => 'persons', 'id' => 'persons',