Newer
Older

Yassine Doghri
committed
<?php

Yassine Doghri
committed

Yassine Doghri
committed
declare(strict_types=1);

Yassine Doghri
committed
/**
* @copyright 2020 Ad Aures

Yassine Doghri
committed
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/

Yassine Doghri
committed
namespace Modules\Admin\Controllers;

Yassine Doghri
committed
use App\Entities\Episode;
use App\Entities\EpisodeComment;

Yassine Doghri
committed
use App\Entities\Location;
use App\Entities\Podcast;
use App\Entities\Post;
use App\Models\EpisodeCommentModel;

Yassine Doghri
committed
use App\Models\EpisodeModel;

Yassine Doghri
committed
use App\Models\MediaModel;

Yassine Doghri
committed
use App\Models\PodcastModel;
use App\Models\PostModel;
use CodeIgniter\Exceptions\PageNotFoundException;
use CodeIgniter\HTTP\RedirectResponse;

Yassine Doghri
committed
use CodeIgniter\I18n\Time;

Yassine Doghri
committed
class EpisodeController extends BaseController

Yassine Doghri
committed
{
protected Podcast $podcast;

Yassine Doghri
committed
protected Episode $episode;

Yassine Doghri
committed
public function _remap(string $method, string ...$params): mixed

Yassine Doghri
committed
{
if (
($podcast = (new PodcastModel())->getPodcastById((int) $params[0])) === null
) {
throw PageNotFoundException::forPageNotFound();
}

Yassine Doghri
committed
$this->podcast = $podcast;

Yassine Doghri
committed
if (count($params) > 1) {
if (
! ($episode = (new EpisodeModel())

Yassine Doghri
committed
->where([
'id' => $params[1],
'podcast_id' => $params[0],

Yassine Doghri
committed
])
->first())
) {
throw PageNotFoundException::forPageNotFound();

Yassine Doghri
committed
}
unset($params[1]);
unset($params[0]);

Yassine Doghri
committed
}
return $this->{$method}(...$params);

Yassine Doghri
committed
}
public function list(): string

Yassine Doghri
committed
{
/** @var ?string $query */
$query = $this->request->getGet('q');
if ($query !== null && $query !== '') {

Yassine Doghri
committed
// Default value for MySQL Full-Text Search's minimum length of words is 4.
// Use LIKE operator as a fallback.
if (strlen($query) < 4) {
$episodes = (new EpisodeModel())
->where('podcast_id', $this->podcast->id)
->like('title', $query)
->orLike('description_markdown', $query)

Yassine Doghri
committed
->orderBy('-`published_at`', '', false)

Yassine Doghri
committed
->orderBy('created_at', 'desc');
} else {
$episodes = (new EpisodeModel())
->where('podcast_id', $this->podcast->id)
->where("MATCH (title, description_markdown) AGAINST ('{$query}')");
}
} else {
$episodes = (new EpisodeModel())
->where('podcast_id', $this->podcast->id)

Yassine Doghri
committed
->orderBy('-`published_at`', '', false)
->orderBy('created_at', 'desc');
}
helper('form');

Yassine Doghri
committed
$data = [
'podcast' => $this->podcast,
'episodes' => $episodes->paginate(10),
'pager' => $episodes->pager,
'query' => $query,

Yassine Doghri
committed
];

Yassine Doghri
committed
0 => $this->podcast->at_handle,
return view('episode/list', $data);

Yassine Doghri
committed
}
public function view(): string
$data = [
'podcast' => $this->podcast,
'episode' => $this->episode,
];

Yassine Doghri
committed
0 => $this->podcast->at_handle,
return view('episode/view', $data);
public function create(): string

Yassine Doghri
committed
{
helper(['form']);

Yassine Doghri
committed
$currentSeasonNumber = (new EpisodeModel())->getCurrentSeasonNumber($this->podcast->id);
$data = [
'podcast' => $this->podcast,

Yassine Doghri
committed
'currentSeasonNumber' => $currentSeasonNumber,
'nextEpisodeNumber' => (new EpisodeModel())->getNextEpisodeNumber($this->podcast->id, $currentSeasonNumber),
];

Yassine Doghri
committed
0 => $this->podcast->at_handle,
return view('episode/create', $data);

Yassine Doghri
committed
public function attemptCreate(): RedirectResponse
{
$rules = [

Yassine Doghri
committed
'slug' => 'max_length[128]',
'audio_file' => 'uploaded[audio_file]|ext_in[audio_file,mp3,m4a]',

Yassine Doghri
committed
'cover' =>
'is_image[cover]|ext_in[cover,jpg,png]|min_dims[cover,1400,1400]|is_image_ratio[cover,1,1]',
'transcript_file' =>

Yassine Doghri
committed
'ext_in[transcript,srt]|permit_empty',
'chapters_file' => 'ext_in[chapters,json]|permit_empty',
];

Yassine Doghri
committed
if ($this->podcast->type === 'serial') {
$rules['episode_number'] = 'required';
}
if (! $this->validate($rules)) {
return redirect()
->back()
->withInput()
->with('errors', $this->validator->getErrors());

Yassine Doghri
committed
}
if ((new EpisodeModel())
->where([
'slug' => $this->request->getPost('slug'),
'podcast_id' => $this->podcast->id,
])
->first()) {
return redirect()
->back()
->withInput()
->with('error', lang('Episode.messages.sameSlugError'));
}

Yassine Doghri
committed
$db = db_connect();
$db->transStart();
$newEpisode = new Episode([
'podcast_id' => $this->podcast->id,
'title' => $this->request->getPost('title'),
'slug' => $this->request->getPost('slug'),
'guid' => null,
'audio' => $this->request->getFile('audio_file'),
'cover' => $this->request->getFile('cover'),
'description_markdown' => $this->request->getPost('description'),
'location' => $this->request->getPost('location_name') === '' ? null : new Location($this->request->getPost(
'location_name'
)),
'transcript' => $this->request->getFile('transcript'),
'chapters' => $this->request->getFile('chapters'),
'parental_advisory' =>
$this->request->getPost('parental_advisory') !== 'undefined'
? $this->request->getPost('parental_advisory')
: null,

Yassine Doghri
committed
'number' => $this->request->getPost('episode_number')

Yassine Doghri
committed
? (int) $this->request->getPost('episode_number')

Yassine Doghri
committed
: null,
'season_number' => $this->request->getPost('season_number')

Yassine Doghri
committed
? (int) $this->request->getPost('season_number')

Yassine Doghri
committed
: null,
'type' => $this->request->getPost('type'),
'is_blocked' => $this->request->getPost('block') === 'yes',

Benjamin Bellamy
committed
'custom_rss_string' => $this->request->getPost('custom_rss'),
'is_premium' => $this->request->getPost('premium') === 'yes',
'created_by' => user_id(),
'updated_by' => user_id(),
'published_at' => null,
]);
$transcriptChoice = $this->request->getPost('transcript-choice');
if ($transcriptChoice === 'upload-file') {
$newEpisode->setTranscript($this->request->getFile('transcript_file'));
} elseif ($transcriptChoice === 'remote-url') {
$newEpisode->transcript_remote_url = $this->request->getPost(
'transcript_remote_url'
) === '' ? null : $this->request->getPost('transcript_remote_url');
}
$chaptersChoice = $this->request->getPost('chapters-choice');
if ($chaptersChoice === 'upload-file') {
$newEpisode->setChapters($this->request->getFile('chapters_file'));
} elseif ($chaptersChoice === 'remote-url') {
$newEpisode->chapters_remote_url = $this->request->getPost(
'chapters_remote_url'
) === '' ? null : $this->request->getPost('chapters_remote_url');
}

Yassine Doghri
committed
$episodeModel = new EpisodeModel();
if (! ($newEpisodeId = $episodeModel->insert($newEpisode, true))) {

Yassine Doghri
committed
$db->transRollback();
return redirect()
->back()
->withInput()

Yassine Doghri
committed
->with('errors', $episodeModel->errors());
}
// update podcast's episode_description_footer_markdown if changed
$this->podcast->episode_description_footer_markdown = $this->request->getPost(
'description_footer'
) === '' ? null : $this->request->getPost('description_footer');
if ($this->podcast->hasChanged('episode_description_footer_markdown')) {
$podcastModel = new PodcastModel();
if (! $podcastModel->update($this->podcast->id, $this->podcast)) {

Yassine Doghri
committed
$db->transRollback();
return redirect()
->back()
->withInput()
->with('errors', $podcastModel->errors());
}
}

Yassine Doghri
committed
$db->transComplete();
return redirect()->route('episode-view', [$this->podcast->id, $newEpisodeId])->with(
'message',
lang('Episode.messages.createSuccess')
);

Yassine Doghri
committed
}
public function edit(): string

Yassine Doghri
committed
{
helper(['form']);
$data = [
'podcast' => $this->podcast,
'episode' => $this->episode,
];

Yassine Doghri
committed

Yassine Doghri
committed
0 => $this->podcast->at_handle,
return view('episode/edit', $data);
}
public function attemptEdit(): RedirectResponse
{
$rules = [

Yassine Doghri
committed
'slug' => 'max_length[128]',
'audio_file' =>
'uploaded[audio_file]|ext_in[audio_file,mp3,m4a]|permit_empty',

Yassine Doghri
committed
'cover' =>
'is_image[cover]|ext_in[cover,jpg,png]|min_dims[cover,1400,1400]|is_image_ratio[cover,1,1]',
'transcript_file' =>
'ext_in[transcript_file,txt,html,srt,json]|permit_empty',
'chapters_file' => 'ext_in[chapters_file,json]|permit_empty',
];

Yassine Doghri
committed
if ($this->podcast->type === 'serial') {
$rules['episode_number'] = 'required';
}
if (! $this->validate($rules)) {
return redirect()
->back()
->withInput()
->with('errors', $this->validator->getErrors());
}

Yassine Doghri
committed
$this->episode->title = $this->request->getPost('title');
$this->episode->slug = $this->request->getPost('slug');

Yassine Doghri
committed
$this->episode->description_markdown = $this->request->getPost('description');
$this->episode->location = $this->request->getPost('location_name') === '' ? null : new Location(
$this->request->getPost('location_name')
);
$this->episode->parental_advisory =
$this->request->getPost('parental_advisory') !== 'undefined'
? $this->request->getPost('parental_advisory')
: null;

Yassine Doghri
committed
$this->episode->number = $this->request->getPost('episode_number')
? $this->request->getPost('episode_number')
: null;
$this->episode->season_number = $this->request->getPost('season_number')
? $this->request->getPost('season_number')
: null;
$this->episode->type = $this->request->getPost('type');
$this->episode->is_blocked = $this->request->getPost('block') === 'yes';

Yassine Doghri
committed
$this->episode->custom_rss_string = $this->request->getPost('custom_rss');
$this->episode->is_premium = $this->request->getPost('premium') === 'yes';

Yassine Doghri
committed

Yassine Doghri
committed
$this->episode->updated_by = (int) user_id();
$this->episode->setAudio($this->request->getFile('audio_file'));
$this->episode->setCover($this->request->getFile('cover'));
// republish on websub hubs upon edit
$this->episode->is_published_on_hubs = false;
$transcriptChoice = $this->request->getPost('transcript-choice');
if ($transcriptChoice === 'upload-file') {
$transcriptFile = $this->request->getFile('transcript_file');

Yassine Doghri
committed
if ($transcriptFile !== null && $transcriptFile->isValid()) {

Yassine Doghri
committed
$this->episode->setTranscript($transcriptFile);
$this->episode->transcript_remote_url = null;
}
} elseif ($transcriptChoice === 'remote-url') {
if (

Yassine Doghri
committed
($transcriptRemoteUrl = $this->request->getPost('transcript_remote_url')) &&
(($transcriptFile = $this->episode->transcript_id) !== null)

Yassine Doghri
committed
(new MediaModel())->deleteMedia($this->episode->transcript);

Yassine Doghri
committed

Yassine Doghri
committed
$this->episode->transcript_remote_url = $transcriptRemoteUrl === '' ? null : $transcriptRemoteUrl;
$chaptersChoice = $this->request->getPost('chapters-choice');
if ($chaptersChoice === 'upload-file') {
$chaptersFile = $this->request->getFile('chapters_file');

Yassine Doghri
committed
if ($chaptersFile !== null && $chaptersFile->isValid()) {

Yassine Doghri
committed
$this->episode->setChapters($chaptersFile);
$this->episode->chapters_remote_url = null;
}
} elseif ($chaptersChoice === 'remote-url') {
if (

Yassine Doghri
committed
($chaptersRemoteUrl = $this->request->getPost('chapters_remote_url')) &&
(($chaptersFile = $this->episode->chapters) !== null)

Yassine Doghri
committed
(new MediaModel())->deleteMedia($this->episode->chapters);

Yassine Doghri
committed

Yassine Doghri
committed
$this->episode->chapters_remote_url = $chaptersRemoteUrl === '' ? null : $chaptersRemoteUrl;
$db = db_connect();
$db->transStart();

Yassine Doghri
committed
$episodeModel = new EpisodeModel();
if (! $episodeModel->update($this->episode->id, $this->episode)) {
$db->transRollback();
return redirect()
->back()
->withInput()

Yassine Doghri
committed
->with('errors', $episodeModel->errors());
}
// update podcast's episode_description_footer_markdown if changed
$this->podcast->episode_description_footer_markdown = $this->request->getPost(
'description_footer'
) === '' ? null : $this->request->getPost('description_footer');
if ($this->podcast->hasChanged('episode_description_footer_markdown')) {
$podcastModel = new PodcastModel();
if (! $podcastModel->update($this->podcast->id, $this->podcast)) {
$db->transRollback();
return redirect()
->back()
->withInput()
->with('errors', $podcastModel->errors());
}
}
$db->transComplete();
return redirect()->route('episode-edit', [$this->podcast->id, $this->episode->id])->with(
'message',
lang('Episode.messages.editSuccess')
);

Yassine Doghri
committed
}
public function transcriptDelete(): RedirectResponse
if ($this->episode->transcript === null) {
return redirect()->back();
}

Yassine Doghri
committed
$mediaModel = new MediaModel();
if (! $mediaModel->deleteMedia($this->episode->transcript)) {
return redirect()
->back()
->withInput()

Yassine Doghri
committed
->with('errors', $mediaModel->errors());
}
return redirect()->back();
}
public function chaptersDelete(): RedirectResponse
if ($this->episode->chapters === null) {
return redirect()->back();
}

Yassine Doghri
committed
$mediaModel = new MediaModel();
if (! $mediaModel->deleteMedia($this->episode->chapters)) {
return redirect()
->back()
->withInput()

Yassine Doghri
committed
->with('errors', $mediaModel->errors());
}
return redirect()->back();
}

Yassine Doghri
committed
public function publish(): string | RedirectResponse
{
if ($this->episode->publication_status === 'not_published') {
helper(['form']);
$data = [
'podcast' => $this->podcast,
'episode' => $this->episode,
];
replace_breadcrumb_params([

Yassine Doghri
committed
0 => $this->podcast->at_handle,
1 => $this->episode->title,
]);
return view('episode/publish', $data);
}

Yassine Doghri
committed
return redirect()->route('episode-view', [$this->podcast->id, $this->episode->id])->with(
'error',
lang('Episode.publish_error')
);
}
public function attemptPublish(): RedirectResponse
{
if ($this->podcast->publication_status === 'published') {
$rules = [
'publication_method' => 'required',
'scheduled_publication_date' =>
'valid_date[Y-m-d H:i]|permit_empty',
];
if (! $this->validate($rules)) {
return redirect()
->back()
->withInput()
->with('errors', $this->validator->getErrors());
}
}
$db = db_connect();
$db->transStart();
$newPost = new Post([
'actor_id' => $this->podcast->actor_id,
'episode_id' => $this->episode->id,
'message' => $this->request->getPost('message'),
'created_by' => user_id(),
]);
if ($this->podcast->publication_status === 'published') {
$publishMethod = $this->request->getPost('publication_method');
if ($publishMethod === 'schedule') {
$scheduledPublicationDate = $this->request->getPost('scheduled_publication_date');
if ($scheduledPublicationDate) {
$this->episode->published_at = Time::createFromFormat(
'Y-m-d H:i',
$scheduledPublicationDate,
$this->request->getPost('client_timezone'),
)->setTimezone(app_timezone());
} else {
$db->transRollback();
return redirect()
->back()
->withInput()
->with('error', lang('Episode.messages.scheduleDateError'));
}
} else {
$this->episode->published_at = Time::now();
}
} elseif ($this->podcast->publication_status === 'scheduled') {
// podcast publication date has already been set
$this->episode->published_at = $this->podcast->published_at->addSeconds(1);
} else {

Yassine Doghri
committed
$this->episode->published_at = Time::now();
}
$newPost->published_at = $this->episode->published_at;

Yassine Doghri
committed
$postModel = new PostModel();
if (! $postModel->addPost($newPost)) {
$db->transRollback();
return redirect()
->back()
->withInput()
->with('errors', $postModel->errors());
}
$episodeModel = new EpisodeModel();
if (! $episodeModel->update($this->episode->id, $this->episode)) {
$db->transRollback();
return redirect()
->back()
->withInput()
->with('errors', $episodeModel->errors());
}
$db->transComplete();
return redirect()->route('episode-view', [$this->podcast->id, $this->episode->id])->with(
'message',
lang('Episode.messages.publishSuccess', [
'publication_status' => $this->episode->publication_status,
])
);
}

Yassine Doghri
committed
public function publishEdit(): string | RedirectResponse
{
if (in_array($this->episode->publication_status, ['scheduled', 'with_podcast'], true)) {
helper(['form']);
$data = [
'podcast' => $this->podcast,
'episode' => $this->episode,
'post' => (new PostModel())
->where([
'actor_id' => $this->podcast->actor_id,
'episode_id' => $this->episode->id,
])
->first(),
];
replace_breadcrumb_params([

Yassine Doghri
committed
0 => $this->podcast->at_handle,
1 => $this->episode->title,
]);
return view('episode/publish_edit', $data);
}

Yassine Doghri
committed
return redirect()->route('episode-view', [$this->podcast->id, $this->episode->id])->with(
'error',
lang('Episode.publish_edit_error')
);
}
public function attemptPublishEdit(): RedirectResponse
{
if ($this->podcast->publication_status === 'published') {
$rules = [
'post_id' => 'required',
'publication_method' => 'required',
'scheduled_publication_date' =>
'valid_date[Y-m-d H:i]|permit_empty',
];
if (! $this->validate($rules)) {
return redirect()
->back()
->withInput()
->with('errors', $this->validator->getErrors());
}
}
$db = db_connect();
$db->transStart();
if ($this->podcast->publication_status === 'published') {
$publishMethod = $this->request->getPost('publication_method');
if ($publishMethod === 'schedule') {
$scheduledPublicationDate = $this->request->getPost('scheduled_publication_date');
if ($scheduledPublicationDate) {
$this->episode->published_at = Time::createFromFormat(
'Y-m-d H:i',
$scheduledPublicationDate,
$this->request->getPost('client_timezone'),
)->setTimezone(app_timezone());
} else {
$db->transRollback();
return redirect()
->back()
->withInput()
->with('error', lang('Episode.messages.scheduleDateError'));
}
} else {
$this->episode->published_at = Time::now();
}
} elseif ($this->podcast->publication_status === 'scheduled') {
// podcast publication date has already been set
$this->episode->published_at = $this->podcast->published_at->addSeconds(1);
} else {

Yassine Doghri
committed
$this->episode->published_at = Time::now();
}
$post = (new PostModel())->getPostById($this->request->getPost('post_id'));

Yassine Doghri
committed
if ($post !== null) {
$post->message = $this->request->getPost('message');
$post->published_at = $this->episode->published_at;

Yassine Doghri
committed
$postModel = new PostModel();
if (! $postModel->editPost($post)) {

Yassine Doghri
committed
$db->transRollback();
return redirect()
->back()
->withInput()
->with('errors', $postModel->errors());

Yassine Doghri
committed
}
}
$episodeModel = new EpisodeModel();
if (! $episodeModel->update($this->episode->id, $this->episode)) {
$db->transRollback();
return redirect()
->back()
->withInput()
->with('errors', $episodeModel->errors());
}
$db->transComplete();
return redirect()->route('episode-view', [$this->podcast->id, $this->episode->id])->with(
'message',
lang('Episode.messages.publishSuccess', [
'publication_status' => $this->episode->publication_status,
])
);
}

Yassine Doghri
committed
public function publishCancel(): RedirectResponse
{
if (in_array($this->episode->publication_status, ['scheduled', 'with_podcast'], true)) {

Yassine Doghri
committed
$db = db_connect();
$db->transStart();
$postModel = new PostModel();
$post = $postModel

Yassine Doghri
committed
->where([
'actor_id' => $this->podcast->actor_id,
'episode_id' => $this->episode->id,
])
->first();
$postModel->removePost($post);

Yassine Doghri
committed
$this->episode->published_at = null;
$episodeModel = new EpisodeModel();
if (! $episodeModel->update($this->episode->id, $this->episode)) {
$db->transRollback();
return redirect()
->back()
->withInput()
->with('errors', $episodeModel->errors());
}
$db->transComplete();
return redirect()->route('episode-view', [$this->podcast->id, $this->episode->id])->with(
'message',
lang('Episode.messages.publishCancelSuccess')
);

Yassine Doghri
committed
}
return redirect()->route('episode-view', [$this->podcast->id, $this->episode->id]);

Yassine Doghri
committed
}

Yassine Doghri
committed
public function publishDateEdit(): string|RedirectResponse
{

Yassine Doghri
committed
// only accessible if episode is already published
if ($this->episode->publication_status !== 'published') {
return redirect()->route('episode-view', [$this->podcast->id, $this->episode->id])->with(
'error',
lang('Episode.publish_date_edit_error')
);
}

Yassine Doghri
committed
helper('form');

Yassine Doghri
committed
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
$data = [
'podcast' => $this->podcast,
'episode' => $this->episode,
];
replace_breadcrumb_params([
0 => $this->podcast->title,
1 => $this->episode->title,
]);
return view('episode/publish_date_edit', $data);
}
/**
* Allows to set an episode's publication date to a past date
*
* Prevents setting a future date as it does not make sense to set a future published date to an already published
* episode. This also prevents any side-effects from occurring.
*/
public function attemptPublishDateEdit(): RedirectResponse
{
$rules = [
'new_publication_date' => 'valid_date[Y-m-d H:i]',
];
if (! $this->validate($rules)) {
return redirect()
->back()
->withInput()
->with('errors', $this->validator->getErrors());
}
$newPublicationDate = $this->request->getPost('new_publication_date');
$newPublicationDate = Time::createFromFormat(
'Y-m-d H:i',
$newPublicationDate,
$this->request->getPost('client_timezone'),
)->setTimezone(app_timezone());
if ($newPublicationDate->isAfter(Time::now())) {
return redirect()
->back()
->withInput()
->with('error', lang('Episode.publish_date_edit_future_error'));
}
$this->episode->published_at = $newPublicationDate;
$episodeModel = new EpisodeModel();
if (! $episodeModel->update($this->episode->id, $this->episode)) {
return redirect()
->back()
->withInput()
->with('errors', $episodeModel->errors());
}

Yassine Doghri
committed
return redirect()->route('episode-view', [$this->podcast->id, $this->episode->id])->with(

Yassine Doghri
committed
'message',
lang('Episode.publish_date_edit_success')

Yassine Doghri
committed
);
}

Yassine Doghri
committed
public function unpublish(): string | RedirectResponse
{
if ($this->episode->publication_status !== 'published') {
return redirect()->route('episode-view', [$this->podcast->id, $this->episode->id])->with(
'error',
lang('Episode.unpublish_error')
);
}
helper(['form']);
$data = [
'podcast' => $this->podcast,
'episode' => $this->episode,
];
replace_breadcrumb_params([
0 => $this->podcast->title,
1 => $this->episode->title,
]);
return view('episode/unpublish', $data);
}
public function attemptUnpublish(): RedirectResponse
{
$rules = [
'understand' => 'required',
];
if (! $this->validate($rules)) {
return redirect()
->back()
->withInput()
->with('errors', $this->validator->getErrors());
}
$db = db_connect();
$db->transStart();
$allPostsLinkedToEpisode = (new PostModel())
->where([
'episode_id' => $this->episode->id,

Yassine Doghri
committed
'in_reply_to_id' => null,
'reblog_of_id' => null,
])
->findAll();
foreach ($allPostsLinkedToEpisode as $post) {
(new PostModel())->removePost($post);
}
$allCommentsLinkedToEpisode = (new EpisodeCommentModel())
->where([
'episode_id' => $this->episode->id,
'in_reply_to_id' => null,
])
->findAll();
foreach ($allCommentsLinkedToEpisode as $comment) {
(new EpisodeCommentModel())->removeComment($comment);
}
// set episode published_at to null to unpublish
$this->episode->published_at = null;
$episodeModel = new EpisodeModel();
if (! $episodeModel->update($this->episode->id, $this->episode)) {
$db->transRollback();
return redirect()
->back()
->withInput()
->with('errors', $episodeModel->errors());
}
// set podcast is_published_on_hubs to false to trigger websub push
(new PodcastModel())->update($this->episode->podcast->id, [
'is_published_on_hubs' => false,
]);
$db->transComplete();
return redirect()->route('episode-view', [$this->podcast->id, $this->episode->id]);
}

Yassine Doghri
committed
public function delete(): string

Yassine Doghri
committed
{

Yassine Doghri
committed
helper(['form']);
$data = [
'podcast' => $this->podcast,
'episode' => $this->episode,
];
replace_breadcrumb_params([

Yassine Doghri
committed
0 => $this->podcast->at_handle,

Yassine Doghri
committed
1 => $this->episode->title,
]);
return view('episode/delete', $data);
}
public function attemptDelete(): RedirectResponse
{
$rules = [
'understand' => 'required',
];
if (! $this->validate($rules)) {
return redirect()
->back()
->withInput()
->with('errors', $this->validator->getErrors());
}
if ($this->episode->published_at !== null) {
return redirect()
->back()
->withInput()
->with('error', lang('Episode.messages.deletePublishedEpisodeError'));
}

Yassine Doghri
committed
$db = db_connect();
$db->transStart();
$episodeModel = new EpisodeModel();
if (! $episodeModel->delete($this->episode->id)) {
$db->transRollback();
return redirect()
->back()
->withInput()
->with('errors', $episodeModel->errors());

Yassine Doghri
committed
}
$episodeMediaList = [$this->episode->transcript, $this->episode->chapters, $this->episode->audio];
//only delete episode cover if different from podcast's
if ($this->episode->cover_id !== null) {
$episodeMediaList[] = $this->episode->cover;
}
//delete episode media records from database
foreach ($episodeMediaList as $episodeMedia) {
if ($episodeMedia !== null && ! $episodeMedia->delete()) {
$db->transRollback();
return redirect()
->back()
->withInput()
->with('error', lang('Episode.messages.deleteError', [
'type' => $episodeMedia->type,
]));

Yassine Doghri
committed
}
$db->transComplete();
$warnings = [];
//remove episode media files from disk
foreach ($episodeMediaList as $episodeMedia) {
if ($episodeMedia !== null && ! $episodeMedia->deleteFile()) {
$warnings[] = lang('Episode.messages.deleteFileError', [
'type' => $episodeMedia->type,
'file_path' => $episodeMedia->file_path,
]);
}
}

Yassine Doghri
committed
if ($warnings !== []) {
return redirect()
->route('episode-list', [$this->podcast->id])
->with('message', lang('Episode.messages.deleteSuccess'))
->with('warnings', $warnings);
}
return redirect()->route('episode-list', [$this->podcast->id])->with(
'message',
lang('Episode.messages.deleteSuccess')
);

Yassine Doghri
committed
}
public function embed(): string
{
helper(['form']);
$data = [
'podcast' => $this->podcast,
'episode' => $this->episode,
'themes' => EpisodeModel::$themes,
];
replace_breadcrumb_params([

Yassine Doghri
committed
0 => $this->podcast->at_handle,
1 => $this->episode->title,
]);
return view('episode/embed', $data);
public function attemptCommentCreate(): RedirectResponse
{
$rules = [
'message' => 'required|max_length[500]',
];
if (! $this->validate($rules)) {
return redirect()
->back()
->withInput()
->with('errors', $this->validator->getErrors());
}
$message = $this->request->getPost('message');
$newComment = new EpisodeComment([
'actor_id' => interact_as_actor_id(),
'episode_id' => $this->episode->id,
'message' => $message,
'created_at' => new Time('now'),
'created_by' => user_id(),
]);
$commentModel = new EpisodeCommentModel();
if (
! $commentModel->addComment($newComment, true)
) {
return redirect()
->back()
->withInput()
->with('errors', $commentModel->errors());
}
// Comment has been successfully created
return redirect()->back();
}
public function attemptCommentReply(string $commentId): RedirectResponse
{