philomena/lib/philomena_web/markdown_renderer.ex

139 lines
3.8 KiB
Elixir
Raw Normal View History

defmodule PhilomenaWeb.MarkdownRenderer do
alias Philomena.Markdown
2021-09-19 23:17:50 +02:00
alias Philomena.Images.Image
alias Philomena.Repo
alias PhilomenaWeb.ImageView
2021-09-19 23:17:50 +02:00
import Phoenix.HTML.Link
import Ecto.Query
def render_one(item, conn) do
hd(render_collection([item], conn))
end
2021-09-19 23:17:50 +02:00
# This is rendered Markdown
# sobelow_skip ["XSS.Raw"]
def render_collection(collection, conn) do
representations =
collection
|> Enum.flat_map(fn %{body: text} ->
2021-10-11 19:36:29 +02:00
find_images(text || "")
end)
|> render_representations(conn)
Enum.map(collection, fn %{body: text} ->
(text || "")
|> Markdown.to_html(representations)
|> Phoenix.HTML.raw()
end)
2021-09-19 23:17:50 +02:00
end
# This is rendered Markdown for use on static pages
# sobelow_skip ["XSS.Raw"]
def render_unsafe(text, conn) do
images = find_images(text)
representations = render_representations(images, conn)
text
|> Markdown.to_html_unsafe(representations)
|> Phoenix.HTML.raw()
end
2021-09-19 23:17:50 +02:00
defp find_images(text) do
Regex.scan(~r/>>(\d+)([tsp])?/, text, capture: :all_but_first)
2021-09-19 23:22:48 +02:00
|> Enum.map(fn matches ->
[Enum.at(matches, 0) |> String.to_integer(), Enum.at(matches, 1) || ""]
end)
2021-09-19 23:17:50 +02:00
|> Enum.filter(fn m -> Enum.at(m, 0) < 2_147_483_647 end)
end
defp load_images(images) do
ids = Enum.map(images, fn m -> Enum.at(m, 0) end)
Image
|> where([i], i.id in ^ids)
|> preload([:sources, tags: :aliases])
2021-09-19 23:17:50 +02:00
|> Repo.all()
|> Map.new(&{&1.id, &1})
end
defp link_suffix(image) do
cond do
not is_nil(image.duplicate_id) ->
" (merged)"
image.hidden_from_users ->
" (deleted)"
2022-03-24 17:31:57 +01:00
not image.approved ->
" (pending approval)"
2021-09-19 23:17:50 +02:00
true ->
""
end
end
defp render_representations(images, conn) do
loaded_images = load_images(images)
images
|> Enum.map(fn group ->
img = loaded_images[Enum.at(group, 0)]
text = "#{Enum.at(group, 0)}#{Enum.at(group, 1)}"
2021-09-19 23:22:48 +02:00
rendered =
cond do
img != nil ->
case group do
2022-03-24 17:31:57 +01:00
[_id, "p"] when not img.hidden_from_users and img.approved ->
Phoenix.View.render(ImageView, "_image_target.html",
embed_display: true,
2021-09-19 23:22:48 +02:00
image: img,
size: ImageView.select_version(img, :medium),
2021-09-19 23:22:48 +02:00
conn: conn
)
2022-03-24 17:31:57 +01:00
[_id, "t"] when not img.hidden_from_users and img.approved ->
Phoenix.View.render(ImageView, "_image_target.html",
embed_display: true,
2021-09-19 23:22:48 +02:00
image: img,
size: ImageView.select_version(img, :small),
2021-09-19 23:22:48 +02:00
conn: conn
)
2022-03-24 17:31:57 +01:00
[_id, "s"] when not img.hidden_from_users and img.approved ->
Phoenix.View.render(ImageView, "_image_target.html",
embed_display: true,
2021-09-19 23:22:48 +02:00
image: img,
size: ImageView.select_version(img, :thumb_small),
2021-09-19 23:22:48 +02:00
conn: conn
)
2022-03-24 18:36:49 +01:00
[_id, suffix] when not img.approved ->
2022-03-24 17:31:57 +01:00
">>#{img.id}#{suffix}#{link_suffix(img)}"
2021-09-19 23:22:48 +02:00
[_id, ""] ->
link(">>#{img.id}#{link_suffix(img)}", to: "/images/#{img.id}")
[_id, suffix] when suffix in ["t", "s", "p"] ->
link(">>#{img.id}#{suffix}#{link_suffix(img)}", to: "/images/#{img.id}")
# This condition should never trigger, but let's leave it here just in case.
[id, suffix] ->
">>#{id}#{suffix}"
end
true ->
">>#{text}"
end
2021-09-19 23:17:50 +02:00
string_contents =
rendered
|> Phoenix.HTML.Safe.to_iodata()
|> IO.iodata_to_binary()
[text, string_contents]
2021-09-19 23:17:50 +02:00
end)
|> Map.new(fn [id, html] -> {id, html} end)
end
end