Commit 3d363f2e authored by Ola Hneini's avatar Ola Hneini Committed by Yassine Doghri
Browse files

feat: add publish feature for podcasts and set draft by default

closes #128, #220
parent 9843ce38
Loading
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -177,6 +177,10 @@ class AddPodcasts extends Migration
                'type' => 'INT',
                'unsigned' => true,
            ],
            'published_at' => [
                'type' => 'DATETIME',
                'null' => true,
            ],
            'created_at' => [
                'type' => 'DATETIME',
            ],
+1 −1
Original line number Diff line number Diff line
@@ -168,7 +168,7 @@ class AuthSeeder extends Seeder
            [
                'name' => 'manage_publications',
                'description' =>
                    'Publish / unpublish episodes & posts of a podcast',
                    'Publish a podcast and publish / unpublish its episodes & posts',
                'has_permission' => ['podcast_admin'],
            ],
            [
+2 −0
Original line number Diff line number Diff line
@@ -541,6 +541,8 @@ class Episode extends Entity
        if ($this->publication_status === null) {
            if ($this->published_at === null) {
                $this->publication_status = 'not_published';
            } elseif ($this->getPodcast()->publication_status !== 'published') {
                $this->publication_status = 'with_podcast';
            } elseif ($this->published_at->isBefore(Time::now())) {
                $this->publication_status = 'published';
            } else {
+24 −0
Original line number Diff line number Diff line
@@ -79,6 +79,8 @@ use RuntimeException;
 * @property string|null $partner_image_url
 * @property int $created_by
 * @property int $updated_by
 * @property string $publication_status;
 * @property Time|null $published_at;
 * @property Time $created_at;
 * @property Time $updated_at;
 *
@@ -147,6 +149,13 @@ class Podcast extends Entity

    protected string $custom_rss_string;

    protected ?string $publication_status = null;

    /**
     * @var string[]
     */
    protected $dates = ['published_at', 'created_at', 'updated_at'];

    /**
     * @var array<string, string>
     */
@@ -459,6 +468,21 @@ class Podcast extends Entity
        return $this->description;
    }

    public function getPublicationStatus(): string
    {
        if ($this->publication_status === null) {
            if ($this->published_at === null) {
                $this->publication_status = 'not_published';
            } elseif ($this->published_at->isBefore(Time::now())) {
                $this->publication_status = 'published';
            } else {
                $this->publication_status = 'scheduled';
            }
        }

        return $this->publication_status;
    }

    /**
     * Returns the podcast's podcasting platform links
     *
+57 −2
Original line number Diff line number Diff line
@@ -116,18 +116,27 @@ if (! function_exists('publication_pill')) {
        $class = match ($publicationStatus) {
            'published' => 'text-pine-500 border-pine-500 bg-pine-50',
            'scheduled' => 'text-red-600 border-red-600 bg-red-50',
            'with_podcast' => 'text-blue-600 border-blue-600 bg-blue-50',
            'not_published' => 'text-gray-600 border-gray-600 bg-gray-50',
            default => 'text-gray-600 border-gray-600 bg-gray-50',
        };

        $title = match ($publicationStatus) {
            'published', 'scheduled' => (string) $publicationDate,
            'with_podcast' => lang('Episode.with_podcast_hint'),
            'not_published' => '',
            default => '',
        };

        $label = lang('Episode.publication_status.' . $publicationStatus);

        return '<span ' . ($publicationDate === null ? '' : 'title="' . $publicationDate . '"') . ' class="px-1 font-semibold border rounded ' .
        return '<span ' . ($title === '' ? '' : 'title="' . $title . '"') . ' class="flex items-center px-1 font-semibold border rounded w-max ' .
            $class .
            ' ' .
            $customClass .
            '">' .
            $label .
            ($publicationStatus === 'with_podcast' ? '<Icon glyph="warning" class="flex-shrink-0 ml-1 text-lg" />' : '') .
            '</span>';
    }
}
@@ -136,7 +145,7 @@ if (! function_exists('publication_pill')) {

if (! function_exists('publication_button')) {
    /**
     * Publication button component
     * Publication button component for episodes
     *
     * Displays the appropriate publication button depending on the publication post.
     */
@@ -149,6 +158,7 @@ if (! function_exists('publication_button')) {
                $variant = 'primary';
                $iconLeft = 'upload-cloud';
                break;
            case 'with_podcast':
            case 'scheduled':
                $label = lang('Episode.publish_edit');
                $route = route_to('episode-publish_edit', $podcastId, $episodeId);
@@ -177,6 +187,51 @@ if (! function_exists('publication_button')) {

// ------------------------------------------------------------------------

if (! function_exists('publication_status_banner')) {
    /**
     * Publication status banner component for podcasts
     *
     * Displays the appropriate banner depending on the podcast's publication status.
     */
    function publication_status_banner(?Time $publicationDate, int $podcastId, string $publicationStatus): string
    {
        switch ($publicationStatus) {
            case 'not_published':
                $bannerDisclaimer = lang('Podcast.publication_status_banner.draft_mode');
                $bannerText = lang('Podcast.publication_status_banner.not_published');
                $linkRoute = route_to('podcast-publish', $podcastId);
                $linkLabel = lang('Podcast.publish');
                break;
            case 'scheduled':
                $bannerDisclaimer = lang('Podcast.publication_status_banner.draft_mode');
                $bannerText = lang('Podcast.publication_status_banner.scheduled', [
                    'publication_date' => local_time($publicationDate),
                ], null, false);
                $linkRoute = route_to('podcast-publish_edit', $podcastId);
                $linkLabel = lang('Podcast.publish_edit');
                break;
            default:
                $bannerDisclaimer = '';
                $bannerText = '';
                $linkRoute = '';
                $linkLabel = '';
                break;
        }

        return <<<CODE_SAMPLE
        <div class="flex items-center px-12 py-1 border-b bg-stripes-gray border-subtle" role="alert">
            <p class="text-gray-900">
                <span class="text-xs font-semibold tracking-wide uppercase">{$bannerDisclaimer}</span>
                <span class="ml-3 text-sm">{$bannerText}</span>
            </p>
            <a href="{$linkRoute}" class="ml-1 text-sm font-semibold underline shadow-xs text-accent-base hover:text-accent-hover hover:no-underline">{$linkLabel}</a>
        </div>
        CODE_SAMPLE;
    }
}

// ------------------------------------------------------------------------

if (! function_exists('episode_numbering')) {
    /**
     * Returns relevant translated episode numbering.
Loading