Ensure podcast publish_at field is always set and sortable and fix sorting issues with the Podcast Episodes admin UI.
This commit is contained in:
parent
eed6811b38
commit
838095eee6
|
@ -189,7 +189,7 @@ const fields: DataTableField[] = [
|
||||||
key: 'is_published',
|
key: 'is_published',
|
||||||
label: $gettext('Is Published'),
|
label: $gettext('Is Published'),
|
||||||
visible: false,
|
visible: false,
|
||||||
sortable: true,
|
sortable: false,
|
||||||
selectable: true
|
selectable: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,7 +14,6 @@ use App\Entity\Repository\PodcastEpisodeRepository;
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use App\OpenApi;
|
use App\OpenApi;
|
||||||
use App\Paginator;
|
|
||||||
use App\Service\Flow\UploadedFile;
|
use App\Service\Flow\UploadedFile;
|
||||||
use Doctrine\Common\Collections\Order;
|
use Doctrine\Common\Collections\Order;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
@ -213,7 +212,6 @@ final class PodcastEpisodesController extends AbstractApiCrudController
|
||||||
->join('e.podcast', 'p')
|
->join('e.podcast', 'p')
|
||||||
->leftJoin('e.media', 'pm')
|
->leftJoin('e.media', 'pm')
|
||||||
->where('e.podcast = :podcast')
|
->where('e.podcast = :podcast')
|
||||||
->orderBy('e.created_at', 'DESC')
|
|
||||||
->setParameter('podcast', $podcast);
|
->setParameter('podcast', $podcast);
|
||||||
|
|
||||||
$queryBuilder = $this->searchQueryBuilder(
|
$queryBuilder = $this->searchQueryBuilder(
|
||||||
|
@ -224,25 +222,18 @@ final class PodcastEpisodesController extends AbstractApiCrudController
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
$episodes = array_map(
|
$queryBuilder = $this->sortQueryBuilder(
|
||||||
fn($row) => $this->viewRecord($row, $request),
|
|
||||||
$queryBuilder->getQuery()->getResult()
|
|
||||||
);
|
|
||||||
|
|
||||||
$episodes = $this->sortArray(
|
|
||||||
$request,
|
$request,
|
||||||
$episodes,
|
$queryBuilder,
|
||||||
[
|
[
|
||||||
'is_published' => 'is_published',
|
'publish_at' => 'e.publish_at',
|
||||||
'publish_at' => 'publish_at',
|
'is_explicit' => 'e.is_explicit',
|
||||||
'is_explicit' => 'is_explicit',
|
|
||||||
],
|
],
|
||||||
'id',
|
'e.publish_at',
|
||||||
Order::Descending
|
Order::Descending
|
||||||
);
|
);
|
||||||
|
|
||||||
$paginator = Paginator::fromArray($episodes, $request);
|
return $this->listPaginatedFromQuery($request, $response, $queryBuilder->getQuery());
|
||||||
return $paginator->write($response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -37,7 +37,7 @@ final class ListEpisodesAction implements SingleActionInterface
|
||||||
->leftJoin('e.playlist_media', 'sm')
|
->leftJoin('e.playlist_media', 'sm')
|
||||||
->where('e.podcast = :podcast')
|
->where('e.podcast = :podcast')
|
||||||
->setParameter('podcast', $podcast)
|
->setParameter('podcast', $podcast)
|
||||||
->andWhere('e.publish_at IS NULL OR e.publish_at <= :publishTime')
|
->andWhere('e.publish_at <= :publishTime')
|
||||||
->setParameter('publishTime', time())
|
->setParameter('publishTime', time())
|
||||||
->andWhere(
|
->andWhere(
|
||||||
'(p.source = :sourceManual AND pm.id IS NOT NULL) OR (p.source = :sourcePlaylist AND sm.id IS NOT NULL)'
|
'(p.source = :sourceManual AND pm.id IS NOT NULL) OR (p.source = :sourcePlaylist AND sm.id IS NOT NULL)'
|
||||||
|
|
|
@ -68,15 +68,14 @@ trait CanSortResults
|
||||||
ServerRequest $request,
|
ServerRequest $request,
|
||||||
Order $defaultSortOrder = Order::Ascending
|
Order $defaultSortOrder = Order::Ascending
|
||||||
): array {
|
): array {
|
||||||
|
$sortValue = Types::stringOrNull($request->getParam('sort'), true);
|
||||||
$sortOrder = Types::stringOrNull($request->getParam('sortOrder'), true);
|
$sortOrder = Types::stringOrNull($request->getParam('sortOrder'), true);
|
||||||
|
|
||||||
$orderEnum = (null !== $sortOrder)
|
|
||||||
? Order::tryFrom(strtoupper($sortOrder)) ?? $defaultSortOrder
|
|
||||||
: $defaultSortOrder;
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Types::stringOrNull($request->getParam('sort'), true),
|
$sortValue,
|
||||||
$orderEnum,
|
(null !== $sortValue && null !== $sortOrder)
|
||||||
|
? Order::tryFrom(strtoupper($sortOrder)) ?? $defaultSortOrder
|
||||||
|
: $defaultSortOrder,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,10 +34,10 @@ final class PodcastEpisode
|
||||||
public int $created_at;
|
public int $created_at;
|
||||||
|
|
||||||
#[OA\Property]
|
#[OA\Property]
|
||||||
public bool $is_published = true;
|
public int $publish_at;
|
||||||
|
|
||||||
#[OA\Property]
|
#[OA\Property]
|
||||||
public ?int $publish_at = null;
|
public bool $is_published = true;
|
||||||
|
|
||||||
#[OA\Property]
|
#[OA\Property]
|
||||||
public bool $has_media = false;
|
public bool $has_media = false;
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Entity\Migration;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
final class Version20240319115513 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Make Podcast Episode publish date always have a value.';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql(
|
||||||
|
<<<'SQL'
|
||||||
|
UPDATE podcast_episode
|
||||||
|
SET publish_at = created_at
|
||||||
|
WHERE publish_at IS NULL
|
||||||
|
SQL
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->addSql('ALTER TABLE podcast_episode CHANGE publish_at publish_at INT NOT NULL');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE podcast_episode CHANGE publish_at publish_at INT DEFAULT NULL');
|
||||||
|
}
|
||||||
|
}
|
|
@ -46,8 +46,8 @@ class PodcastEpisode implements IdentifiableEntityInterface
|
||||||
#[Assert\NotBlank]
|
#[Assert\NotBlank]
|
||||||
protected string $description;
|
protected string $description;
|
||||||
|
|
||||||
#[ORM\Column(nullable: true)]
|
#[ORM\Column]
|
||||||
protected ?int $publish_at = null;
|
protected int $publish_at;
|
||||||
|
|
||||||
#[ORM\Column]
|
#[ORM\Column]
|
||||||
protected bool $explicit;
|
protected bool $explicit;
|
||||||
|
@ -63,6 +63,7 @@ class PodcastEpisode implements IdentifiableEntityInterface
|
||||||
{
|
{
|
||||||
$this->podcast = $podcast;
|
$this->podcast = $podcast;
|
||||||
$this->created_at = time();
|
$this->created_at = time();
|
||||||
|
$this->publish_at = time();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPodcast(): Podcast
|
public function getPodcast(): Podcast
|
||||||
|
@ -126,14 +127,14 @@ class PodcastEpisode implements IdentifiableEntityInterface
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPublishAt(): ?int
|
public function getPublishAt(): int
|
||||||
{
|
{
|
||||||
return $this->publish_at;
|
return $this->publish_at;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setPublishAt(?int $publishAt): self
|
public function setPublishAt(?int $publishAt): self
|
||||||
{
|
{
|
||||||
$this->publish_at = $publishAt;
|
$this->publish_at = $publishAt ?? $this->created_at;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -181,7 +182,7 @@ class PodcastEpisode implements IdentifiableEntityInterface
|
||||||
|
|
||||||
public function isPublished(): bool
|
public function isPublished(): bool
|
||||||
{
|
{
|
||||||
if ($this->getPublishAt() !== null && $this->getPublishAt() > time()) {
|
if ($this->getPublishAt() > time()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ final class PodcastRepository extends Repository
|
||||||
LEFT JOIN pe.playlist_media sm
|
LEFT JOIN pe.playlist_media sm
|
||||||
WHERE
|
WHERE
|
||||||
((p.source = :sourceManual AND pm.id IS NOT NULL) OR (p.source = :sourcePlaylist AND sm.id IS NOT NULL))
|
((p.source = :sourceManual AND pm.id IS NOT NULL) OR (p.source = :sourcePlaylist AND sm.id IS NOT NULL))
|
||||||
AND (pe.publish_at IS NULL OR pe.publish_at <= :time)
|
AND (pe.publish_at <= :time)
|
||||||
DQL
|
DQL
|
||||||
)->setParameter('time', time())
|
)->setParameter('time', time())
|
||||||
->setParameter('sourceManual', PodcastSources::Manual->value)
|
->setParameter('sourceManual', PodcastSources::Manual->value)
|
||||||
|
|
Loading…
Reference in New Issue