fix: issue #7 rebuild media links to get gallery working again

This commit is contained in:
2026-07-05 14:44:47 +02:00
parent 8e60fe31a5
commit 7dfcd78abd
13 changed files with 272 additions and 49 deletions

View File

@@ -0,0 +1,62 @@
defmodule BDS.Media.LinkRestoreFreshTest do
use ExUnit.Case, async: false
import Ecto.Query
alias BDS.Media
alias BDS.Media.Media, as: MediaRecord
alias BDS.Posts.PostMedia
alias BDS.Repo
setup do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(Repo)
Ecto.Adapters.SQL.Sandbox.mode(Repo, {:shared, self()})
temp_dir = Path.join(System.tmp_dir!(), "bds-freshlink-#{System.unique_integer([:positive])}")
File.mkdir_p!(temp_dir)
on_exit(fn -> File.rm_rf(temp_dir) end)
{:ok, project} = BDS.Projects.create_project(%{name: "Fresh", data_path: temp_dir})
{:ok, _} = BDS.Metadata.update_project_metadata(project.id, %{main_language: "en"})
{:ok, post} =
BDS.Posts.create_post(%{
project_id: project.id,
title: "Gallery Post",
content: "[[gallery]]",
language: "en"
})
source = Path.join(temp_dir, "fresh.jpg")
File.write!(source, "fake jpeg")
{:ok, media} = Media.import_media(%{project_id: project.id, source_path: source})
{:ok, _} = Media.link_media_to_post(media.id, post.id)
%{project: project, post: post, media: media}
end
test "fresh media rebuild (media record gone, only files on disk) restores links", %{
project: project,
post: post,
media: media
} do
# Sidecar on disk should carry the link.
sidecar_path = Path.join(project.data_path, media.sidecar_path)
assert File.exists?(sidecar_path)
contents = File.read!(sidecar_path)
assert contents =~ "linkedPostIds"
assert contents =~ post.id
# Simulate a fresh DB: drop the media record AND its links entirely.
Repo.delete_all(from pm in PostMedia, where: pm.media_id == ^media.id)
Repo.delete_all(from m in MediaRecord, where: m.id == ^media.id)
assert Repo.aggregate(from(m in MediaRecord, where: m.id == ^media.id), :count) == 0
assert {:ok, _} = BDS.Media.rebuild_media_from_files(project.id)
# Media re-inserted from sidecar.
assert Repo.aggregate(from(m in MediaRecord, where: m.project_id == ^project.id), :count) == 1
# Link restored so the post's media list is populated again.
assert Repo.aggregate(from(pm in PostMedia, where: pm.post_id == ^post.id), :count) == 1
end
end

View File

@@ -69,4 +69,51 @@ defmodule BDS.Media.LinkRestoreTest do
assert {:ok, _} = BDS.Media.rebuild_media_from_files(project.id)
assert link_count(post.id, media.id) == 1
end
test "rebuild_media_links rebuilds gallery links from sidecars", %{
project: project,
post: post,
media: media
} do
# Simulate a project whose junction table was never populated even though
# the media sidecar references the post (the reported gallery regression).
Repo.delete_all(from pm in PostMedia, where: pm.media_id == ^media.id)
assert link_count(post.id, media.id) == 0
assert {:ok, %{media: 1, links: 1}} = BDS.Media.rebuild_media_links(project.id)
assert link_count(post.id, media.id) == 1
end
test "rebuild_media_links drops stale junction links not present in sidecars", %{
project: project,
post: post,
media: media
} do
{:ok, other_post} =
BDS.Posts.create_post(%{
project_id: project.id,
title: "Unrelated Post",
content: "no gallery here",
language: "en"
})
# A junction row that drifted from the sidecar: the media is linked to a
# post its sidecar does not reference. The sidecar is the source of truth,
# so rebuild must drop this link.
Repo.insert!(%PostMedia{
id: Ecto.UUID.generate(),
project_id: project.id,
post_id: other_post.id,
media_id: media.id,
sort_order: 5,
created_at: 0
})
assert {:ok, %{links: 1}} = BDS.Media.rebuild_media_links(project.id)
# The real (sidecar-backed) link survives, the drifted link is gone.
assert link_count(post.id, media.id) == 1
assert link_count(other_post.id, media.id) == 0
end
end