fix: hopefully full fix for rebuilding
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -688,7 +688,10 @@ defmodule BDS.Posts do
|
|||||||
published_excerpt: nil
|
published_excerpt: nil
|
||||||
}
|
}
|
||||||
|
|
||||||
post = Repo.get_by(Post, project_id: project_id, slug: attrs.slug) || %Post{}
|
post =
|
||||||
|
Repo.get(Post, attrs.id) ||
|
||||||
|
Repo.get_by(Post, project_id: project_id, file_path: rebuild_file.relative_path) ||
|
||||||
|
Repo.get_by(Post, project_id: project_id, slug: attrs.slug) || %Post{}
|
||||||
|
|
||||||
post
|
post
|
||||||
|> Post.changeset(attrs)
|
|> Post.changeset(attrs)
|
||||||
@@ -700,7 +703,7 @@ defmodule BDS.Posts do
|
|||||||
defp upsert_post_translation_from_rebuild_file(project_id, rebuild_file) do
|
defp upsert_post_translation_from_rebuild_file(project_id, rebuild_file) do
|
||||||
fields = rebuild_file.fields
|
fields = rebuild_file.fields
|
||||||
source_post_id = Map.fetch!(fields, "translationFor")
|
source_post_id = Map.fetch!(fields, "translationFor")
|
||||||
source_post = Repo.get!(Post, source_post_id)
|
source_post = Repo.get_by!(Post, project_id: project_id, id: source_post_id)
|
||||||
now = Persistence.now_ms()
|
now = Persistence.now_ms()
|
||||||
language = normalize_language(Map.fetch!(fields, "language"))
|
language = normalize_language(Map.fetch!(fields, "language"))
|
||||||
|
|
||||||
|
|||||||
@@ -508,6 +508,116 @@ defmodule BDS.PostsTest do
|
|||||||
"Introducing Thirty Ten, my guide to creating a Twenty Ten Child Theme | aaron.jorb.inaaron.jorb.in"
|
"Introducing Thirty Ten, my guide to creating a Twenty Ten Child Theme | aaron.jorb.inaaron.jorb.in"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "rebuild_posts_from_files realigns an existing slug match to the canonical file id before importing translations",
|
||||||
|
%{project: project} do
|
||||||
|
assert {:ok, _stale_post} =
|
||||||
|
BDS.Posts.create_post(%{
|
||||||
|
project_id: project.id,
|
||||||
|
title: "Old Title",
|
||||||
|
slug: "chimera",
|
||||||
|
content: "stale body"
|
||||||
|
})
|
||||||
|
|
||||||
|
posts_dir = Path.join([BDS.Projects.project_data_dir(project), "posts", "2026", "04"])
|
||||||
|
File.mkdir_p!(posts_dir)
|
||||||
|
|
||||||
|
File.write!(
|
||||||
|
Path.join(posts_dir, "chimera.md"),
|
||||||
|
[
|
||||||
|
"---",
|
||||||
|
"id: canonical-post-id",
|
||||||
|
"title: Chimera Source",
|
||||||
|
"slug: chimera",
|
||||||
|
"status: published",
|
||||||
|
"language: de",
|
||||||
|
"createdAt: 2024-03-30T21:20:00.000Z",
|
||||||
|
"updatedAt: 2024-03-31T21:20:00.000Z",
|
||||||
|
"publishedAt: 2024-04-01T21:20:00.000Z",
|
||||||
|
"---",
|
||||||
|
"Quelle",
|
||||||
|
""
|
||||||
|
]
|
||||||
|
|> Enum.join("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
File.write!(
|
||||||
|
Path.join(posts_dir, "chimera.en.md"),
|
||||||
|
[
|
||||||
|
"---",
|
||||||
|
"id: translation-from-old-app",
|
||||||
|
"translationFor: canonical-post-id",
|
||||||
|
"language: en",
|
||||||
|
"title: Chimera",
|
||||||
|
"excerpt: Imported translation",
|
||||||
|
"---",
|
||||||
|
"Translated body",
|
||||||
|
""
|
||||||
|
]
|
||||||
|
|> Enum.join("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
assert {:ok, [post]} = BDS.Posts.rebuild_posts_from_files(project.id)
|
||||||
|
assert post.id == "canonical-post-id"
|
||||||
|
assert post.slug == "chimera"
|
||||||
|
|
||||||
|
assert {:ok, [translation]} = BDS.Posts.list_post_translations(post.id)
|
||||||
|
assert translation.translation_for == post.id
|
||||||
|
end
|
||||||
|
|
||||||
|
test "rebuild_posts_from_files repairs a stale row that matches by file path but has a broken slug",
|
||||||
|
%{project: project} do
|
||||||
|
now = BDS.Persistence.now_ms()
|
||||||
|
relative_path = "posts/2010/11/chimera.md"
|
||||||
|
|
||||||
|
stale_post =
|
||||||
|
%BDS.Posts.Post{}
|
||||||
|
|> BDS.Posts.Post.changeset(%{
|
||||||
|
id: "stale-post-id",
|
||||||
|
project_id: project.id,
|
||||||
|
title: ">-",
|
||||||
|
slug: ">-",
|
||||||
|
status: :published,
|
||||||
|
created_at: now,
|
||||||
|
updated_at: now,
|
||||||
|
file_path: relative_path,
|
||||||
|
do_not_translate: false
|
||||||
|
})
|
||||||
|
|> BDS.Repo.insert!()
|
||||||
|
|
||||||
|
posts_dir = Path.join([BDS.Projects.project_data_dir(project), "posts", "2010", "11"])
|
||||||
|
File.mkdir_p!(posts_dir)
|
||||||
|
|
||||||
|
File.write!(
|
||||||
|
Path.join(posts_dir, "chimera.md"),
|
||||||
|
[
|
||||||
|
"---",
|
||||||
|
"id: canonical-post-id",
|
||||||
|
"title: Chimera Source",
|
||||||
|
"slug: chimera",
|
||||||
|
"status: published",
|
||||||
|
"language: de",
|
||||||
|
"createdAt: 2024-03-30T21:20:00.000Z",
|
||||||
|
"updatedAt: 2024-03-31T21:20:00.000Z",
|
||||||
|
"publishedAt: 2024-04-01T21:20:00.000Z",
|
||||||
|
"---",
|
||||||
|
"Quelle",
|
||||||
|
""
|
||||||
|
]
|
||||||
|
|> Enum.join("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
assert {:ok, [post]} = BDS.Posts.rebuild_posts_from_files(project.id)
|
||||||
|
assert post.id == "canonical-post-id"
|
||||||
|
assert post.slug == "chimera"
|
||||||
|
|
||||||
|
posts =
|
||||||
|
BDS.Repo.all(BDS.Posts.Post)
|
||||||
|
|> Enum.filter(&(&1.project_id == project.id))
|
||||||
|
|
||||||
|
assert length(posts) == 1
|
||||||
|
refute BDS.Repo.get(BDS.Posts.Post, stale_post.id)
|
||||||
|
end
|
||||||
|
|
||||||
defp errors_on(changeset) do
|
defp errors_on(changeset) do
|
||||||
Ecto.Changeset.traverse_errors(changeset, fn {message, opts} ->
|
Ecto.Changeset.traverse_errors(changeset, fn {message, opts} ->
|
||||||
Regex.replace(~r"%{(\w+)}", message, fn _, key ->
|
Regex.replace(~r"%{(\w+)}", message, fn _, key ->
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ defmodule BDS.RealBlogRebuildDiagnosticTest do
|
|||||||
if is_binary(@real_blog_path) and @real_blog_path != "" do
|
if is_binary(@real_blog_path) and @real_blog_path != "" do
|
||||||
setup do
|
setup do
|
||||||
:ok = Ecto.Adapters.SQL.Sandbox.checkout(BDS.Repo, ownership_timeout: 600_000)
|
:ok = Ecto.Adapters.SQL.Sandbox.checkout(BDS.Repo, ownership_timeout: 600_000)
|
||||||
|
Ecto.Adapters.SQL.Sandbox.mode(BDS.Repo, {:shared, self()})
|
||||||
|
|
||||||
now = BDS.Persistence.now_ms()
|
now = BDS.Persistence.now_ms()
|
||||||
unique = Integer.to_string(System.unique_integer([:positive]))
|
unique = Integer.to_string(System.unique_integer([:positive]))
|
||||||
@@ -34,6 +35,43 @@ defmodule BDS.RealBlogRebuildDiagnosticTest do
|
|||||||
test "rebuilds media from the external real blog path", %{project: project} do
|
test "rebuilds media from the external real blog path", %{project: project} do
|
||||||
assert {:ok, _media} = BDS.Maintenance.rebuild_from_filesystem(project.id, "media")
|
assert {:ok, _media} = BDS.Maintenance.rebuild_from_filesystem(project.id, "media")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "shell rebuild task rebuilds posts from the external real blog path", %{project: project} do
|
||||||
|
:ok = BDS.Tasks.clear_finished()
|
||||||
|
assert {:ok, _active} = BDS.Projects.set_active_project(project.id)
|
||||||
|
|
||||||
|
assert {:ok, result} = BDS.Desktop.ShellCommands.execute("rebuild_database")
|
||||||
|
assert result.kind == "task_queued"
|
||||||
|
|
||||||
|
task =
|
||||||
|
wait_for_named_task(
|
||||||
|
"Rebuild Posts From Files",
|
||||||
|
&(&1.status in [:completed, :failed]),
|
||||||
|
600_000
|
||||||
|
)
|
||||||
|
|
||||||
|
assert task.status == :completed
|
||||||
|
end
|
||||||
|
|
||||||
|
test "rebuilds posts from the external real blog path twice in the same project", %{project: project} do
|
||||||
|
assert {:ok, _posts} = BDS.Maintenance.rebuild_from_filesystem(project.id, "post")
|
||||||
|
assert {:ok, _posts} = BDS.Maintenance.rebuild_from_filesystem(project.id, "post")
|
||||||
|
end
|
||||||
|
|
||||||
|
defp wait_for_named_task(_name, _matcher, timeout) when timeout <= 0 do
|
||||||
|
flunk("named task did not reach expected state")
|
||||||
|
end
|
||||||
|
|
||||||
|
defp wait_for_named_task(name, matcher, timeout) do
|
||||||
|
task = Enum.find(BDS.Tasks.list_tasks(), &(&1.name == name))
|
||||||
|
|
||||||
|
if task && matcher.(task) do
|
||||||
|
task
|
||||||
|
else
|
||||||
|
Process.sleep(100)
|
||||||
|
wait_for_named_task(name, matcher, timeout - 100)
|
||||||
|
end
|
||||||
|
end
|
||||||
else
|
else
|
||||||
@tag skip: "BDS_REAL_BLOG_PATH not set"
|
@tag skip: "BDS_REAL_BLOG_PATH not set"
|
||||||
test "rebuilds posts from the external real blog path" do
|
test "rebuilds posts from the external real blog path" do
|
||||||
@@ -42,5 +80,13 @@ defmodule BDS.RealBlogRebuildDiagnosticTest do
|
|||||||
@tag skip: "BDS_REAL_BLOG_PATH not set"
|
@tag skip: "BDS_REAL_BLOG_PATH not set"
|
||||||
test "rebuilds media from the external real blog path" do
|
test "rebuilds media from the external real blog path" do
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@tag skip: "BDS_REAL_BLOG_PATH not set"
|
||||||
|
test "shell rebuild task rebuilds posts from the external real blog path" do
|
||||||
|
end
|
||||||
|
|
||||||
|
@tag skip: "BDS_REAL_BLOG_PATH not set"
|
||||||
|
test "rebuilds posts from the external real blog path twice in the same project" do
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user