castopod/modules/PodcastImport/Controllers/PodcastImportController.php

214 lines
7.0 KiB
PHP

<?php
declare(strict_types=1);
/**
* @copyright 2023 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace Modules\PodcastImport\Controllers;
use App\Entities\Podcast;
use App\Models\CategoryModel;
use App\Models\LanguageModel;
use App\Models\PodcastModel;
use CodeIgniter\Exceptions\PageNotFoundException;
use CodeIgniter\HTTP\RedirectResponse;
use CodeIgniter\I18n\Time;
use Exception;
use Modules\Admin\Controllers\BaseController;
use Modules\PodcastImport\Entities\PodcastImportTask;
use Modules\PodcastImport\Entities\TaskStatus;
class PodcastImportController extends BaseController
{
public function list(): string
{
helper('podcast_import');
return view('import/queue', [
'podcastImportsQueue' => get_import_tasks(),
]);
}
public function podcastList(int $podcastId): string
{
if (! ($podcast = (new PodcastModel())->getPodcastById($podcastId)) instanceof Podcast) {
throw PageNotFoundException::forPageNotFound();
}
helper('podcast_import');
replace_breadcrumb_params([
0 => $podcast->at_handle,
]);
return view('import/podcast_queue', [
'podcast' => $podcast,
'podcastImportsQueue' => get_import_tasks($podcast->handle),
]);
}
public function addToQueueView(): string
{
helper(['form', 'misc']);
$languageOptions = (new LanguageModel())->getLanguageOptions();
$categoryOptions = (new CategoryModel())->getCategoryOptions();
$data = [
'languageOptions' => $languageOptions,
'categoryOptions' => $categoryOptions,
'browserLang' => get_browser_language($this->request->getServer('HTTP_ACCEPT_LANGUAGE')),
];
return view('import/add_to_queue', $data);
}
public function addToQueueAction(): RedirectResponse
{
$rules = [
'handle' => 'required|regex_match[/^[a-zA-Z0-9\_]{1,32}$/]',
'imported_feed_url' => 'required|valid_url_strict',
'language' => 'required',
'category' => 'required',
];
if (! $this->validate($rules)) {
return redirect()
->back()
->withInput()
->with('errors', $this->validator->getErrors());
}
$validData = $this->validator->getValidated();
// TODO: check that handle is not already in use
$importTask = new PodcastImportTask([
'handle' => $validData['handle'],
'feed_url' => $validData['imported_feed_url'],
'language' => $validData['language'],
'category' => $validData['category'],
'status' => TaskStatus::Queued,
'created_by' => user_id(),
'updated_by' => user_id(),
'created_at' => Time::now(),
'updated_at' => Time::now(),
]);
$importTask->save();
return redirect()->route('all-podcast-imports')
->with('message', lang('PodcastImport.messages.importTaskQueued'));
}
public function syncImport(int $podcastId): string
{
if (! ($podcast = (new PodcastModel())->getPodcastById($podcastId)) instanceof Podcast) {
throw PageNotFoundException::forPageNotFound();
}
helper('form');
replace_breadcrumb_params([
0 => $podcast->at_handle,
]);
return view('import/podcast_sync', [
'podcast' => $podcast,
]);
}
public function syncImportAttempt(int $podcastId): RedirectResponse
{
if (! ($podcast = (new PodcastModel())->getPodcastById($podcastId)) instanceof Podcast) {
throw PageNotFoundException::forPageNotFound();
}
$rules = [
'feed_url' => 'valid_url_strict',
];
if (! $this->validate($rules)) {
return redirect()
->back()
->withInput()
->with('errors', $this->validator->getErrors());
}
$validData = $this->validator->getValidated();
// create update task in podcastImport
$importTask = new PodcastImportTask([
'handle' => $podcast->handle,
'feed_url' => $validData['feed_url'],
'language' => $podcast->language_code,
'category' => $podcast->category_id,
'status' => TaskStatus::Queued,
'created_by' => user_id(),
'updated_by' => user_id(),
'created_at' => Time::now(),
'updated_at' => Time::now(),
]);
$importTask->save();
return redirect()->route('podcast-imports', [$podcastId])
->with('message', lang('PodcastImport.messages.syncTaskQueued'));
}
public function taskAction(string $taskId, string $action): RedirectResponse
{
/** @var array<string, PodcastImportTask> $importQueue */
$importQueue = service('settings')
->get('Import.queue') ?? [];
if (! array_key_exists($taskId, $importQueue)) {
throw PageNotFoundException::forPageNotFound();
}
$importTask = $importQueue[$taskId];
switch ($action) {
case 'cancel':
if ($importTask->status === TaskStatus::Running || $importTask->status === TaskStatus::Queued) {
$importTask->cancel();
return redirect()->back()
->with('message', lang('PodcastImport.messages.canceled'));
}
return redirect()->back()
->with('error', lang('PodcastImport.messages.notRunning'));
case 'retry':
if ($importTask->status === TaskStatus::Running || $importTask->status === TaskStatus::Queued) {
return redirect()->back()
->with('error', lang('PodcastImport.messages.alreadyRunning'));
}
$newImportTask = new PodcastImportTask([
'handle' => $importTask->handle,
'feed_url' => $importTask->feed_url,
'language' => $importTask->language,
'category' => $importTask->category,
'status' => TaskStatus::Queued,
'created_by' => user_id(),
'updated_by' => user_id(),
'created_at' => Time::now(),
'updated_at' => Time::now(),
]);
$newImportTask->save();
return redirect()->back()
->with('message', lang('PodcastImport.messages.retried'));
case 'delete':
$importTask->delete();
return redirect()->back()
->with('message', lang('PodcastImport.messages.deleted'));
default:
throw new Exception('Task action ' . $action . ' was not implemented');
}
}
}