From 0305d80051d3eda7e96608dbf13633df154a82db Mon Sep 17 00:00:00 2001 From: Chili Palmer Date: Thu, 28 May 2026 22:24:07 +0200 Subject: [PATCH] fix: A1-6 preview prefers draft content over published files for on-demand rendering --- lib/bds/preview/router.ex | 24 +++++---- test/bds/preview_test.exs | 101 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 10 deletions(-) diff --git a/lib/bds/preview/router.ex b/lib/bds/preview/router.ex index 01d8910..de7450b 100644 --- a/lib/bds/preview/router.ex +++ b/lib/bds/preview/router.ex @@ -406,35 +406,35 @@ defmodule BDS.Preview.Router do |> MapSet.new() project_id - |> load_all_published_posts() + |> load_previewable_posts() |> Enum.reject(fn post -> Enum.any?(post.categories || [], &MapSet.member?(excluded, &1)) end) end - defp load_all_published_posts(project_id) do + defp load_previewable_posts(project_id) do Repo.all( from p in Post, - where: p.project_id == ^project_id and p.status == :published, + where: p.project_id == ^project_id and p.status in [:published, :draft], order_by: [desc: p.created_at, desc: p.published_at, asc: p.slug] ) end defp load_published_posts_by_category(project_id, category) do project_id - |> load_all_published_posts() + |> load_previewable_posts() |> Enum.filter(fn post -> category in (post.categories || []) end) end defp load_published_posts_by_tag(project_id, tag) do project_id - |> load_all_published_posts() + |> load_previewable_posts() |> Enum.filter(fn post -> tag in (post.tags || []) end) end defp load_published_posts_by_year(project_id, year) do project_id - |> load_all_published_posts() + |> load_previewable_posts() |> Enum.filter(fn post -> {post_year, _, _} = Paths.local_date_parts!(post.created_at) post_year == year @@ -443,7 +443,7 @@ defmodule BDS.Preview.Router do defp load_published_posts_by_month(project_id, year, month) do project_id - |> load_all_published_posts() + |> load_previewable_posts() |> Enum.filter(fn post -> {post_year, post_month, _} = Paths.local_date_parts!(post.created_at) post_year == year and post_month == month @@ -452,7 +452,7 @@ defmodule BDS.Preview.Router do defp load_published_posts_by_day(project_id, year, month, day) do project_id - |> load_all_published_posts() + |> load_previewable_posts() |> Enum.filter(fn post -> {post_year, post_month, post_day} = Paths.local_date_parts!(post.created_at) post_year == year and post_month == month and post_day == day @@ -462,7 +462,9 @@ defmodule BDS.Preview.Router do defp find_post_by_slug_and_date(project_id, slug, year, month, day) do case Repo.one( from p in Post, - where: p.project_id == ^project_id and p.slug == ^slug and p.status == :published + where: + p.project_id == ^project_id and p.slug == ^slug and + p.status in [:published, :draft] ) do nil -> nil @@ -481,7 +483,9 @@ defmodule BDS.Preview.Router do defp find_page_by_slug(project_id, slug) do case Repo.one( from p in Post, - where: p.project_id == ^project_id and p.slug == ^slug and p.status == :published + where: + p.project_id == ^project_id and p.slug == ^slug and + p.status in [:published, :draft] ) do %Post{categories: categories} = post -> if "page" in (categories || []), do: post, else: nil diff --git a/test/bds/preview_test.exs b/test/bds/preview_test.exs index bfd1a3b..6d8b7b7 100644 --- a/test/bds/preview_test.exs +++ b/test/bds/preview_test.exs @@ -605,6 +605,107 @@ defmodule BDS.PreviewTest do assert :ok = BDS.Preview.stop_preview(project.id) end + test "on-demand rendering: draft post (never published) is visible and uses DB content", %{ + project: project + } do + assert {:ok, _metadata} = + Metadata.update_project_metadata(project.id, %{ + main_language: "en", + blog_languages: ["en"] + }) + + assert {:ok, post} = + Posts.create_post(%{ + project_id: project.id, + title: "Pure Draft", + content: "Draft-only content", + language: "en" + }) + + assert post.status == :draft + assert {:ok, _server} = BDS.Preview.start_preview(project.id) + + datetime = DateTime.from_unix!(post.created_at, :millisecond) + y = Integer.to_string(datetime.year) + m = String.pad_leading(Integer.to_string(datetime.month), 2, "0") + d = String.pad_leading(Integer.to_string(datetime.day), 2, "0") + + assert {:ok, %{body: html, content_type: "text/html"}} = + BDS.Preview.request(project.id, "/#{y}/#{m}/#{d}/#{post.slug}") + + assert html =~ "Pure Draft" + assert html =~ "Draft-only content" + + assert :ok = BDS.Preview.stop_preview(project.id) + end + + test "on-demand rendering: published-then-edited post shows draft DB content over file", %{ + project: project + } do + assert {:ok, _metadata} = + Metadata.update_project_metadata(project.id, %{ + main_language: "en", + blog_languages: ["en"] + }) + + assert {:ok, post} = + Posts.create_post(%{ + project_id: project.id, + title: "Published Then Edited", + content: "Original content", + language: "en" + }) + + assert {:ok, published} = Posts.publish_post(post.id) + + {:ok, edited} = + Posts.update_post(published.id, %{ + title: "Edited Title", + content: "Edited draft content" + }) + + assert {:ok, _server} = BDS.Preview.start_preview(project.id) + + datetime = DateTime.from_unix!(edited.created_at, :millisecond) + y = Integer.to_string(datetime.year) + m = String.pad_leading(Integer.to_string(datetime.month), 2, "0") + d = String.pad_leading(Integer.to_string(datetime.day), 2, "0") + + assert {:ok, %{body: html, content_type: "text/html"}} = + BDS.Preview.request(project.id, "/#{y}/#{m}/#{d}/#{edited.slug}") + + assert html =~ "Edited Title" + assert html =~ "Edited draft content" + refute html =~ "Original content" + + assert :ok = BDS.Preview.stop_preview(project.id) + end + + test "on-demand rendering: draft posts appear in home listing", %{project: project} do + assert {:ok, _metadata} = + Metadata.update_project_metadata(project.id, %{ + main_language: "en", + blog_languages: ["en"] + }) + + assert {:ok, _draft} = + Posts.create_post(%{ + project_id: project.id, + title: "Draft In List", + content: "Draft list body", + language: "en" + }) + + assert {:ok, _server} = BDS.Preview.start_preview(project.id) + + assert {:ok, %{body: html, content_type: "text/html"}} = + BDS.Preview.request(project.id, "/") + + assert html =~ "Draft In List" + + assert :ok = BDS.Preview.stop_preview(project.id) + end + test "preview query params can override the rendered theme for generated and draft pages", %{ project: project } do