Files
bDS2/lib/bds/rendering/links_and_languages.ex

140 lines
4.3 KiB
Elixir

defmodule BDS.Rendering.LinksAndLanguages do
@moduledoc false
import Ecto.Query
alias BDS.Media.Media, as: MediaAsset
alias BDS.Persistence
alias BDS.PostLinks
alias BDS.Posts.Post
alias BDS.Repo
@spec canonical_post_path_by_slug(String.t(), String.t()) :: %{String.t() => String.t()}
def canonical_post_path_by_slug(project_id, main_language) do
posts =
Repo.all(
from post in Post, where: post.project_id == ^project_id and post.status == :published
)
translations =
Repo.all(
from translation in BDS.Posts.Translation,
where: translation.project_id == ^project_id and translation.status == :published
)
post_by_id = Map.new(posts, fn post -> {post.id, post} end)
post_paths =
Enum.into(posts, %{}, fn post ->
{post.slug, post_path(post, nil)}
end)
Enum.reduce(translations, post_paths, fn translation, acc ->
case Map.get(post_by_id, translation.translation_for) do
nil -> acc
post -> Map.put(acc, post.slug, post_path(post, translation.language, main_language))
end
end)
end
@spec canonical_media_path_by_source_path(String.t()) :: %{String.t() => String.t()}
def canonical_media_path_by_source_path(project_id) do
Repo.all(from media in MediaAsset, where: media.project_id == ^project_id)
|> Enum.reduce(%{}, fn media, acc ->
datetime = Persistence.from_unix_ms!(media.created_at)
source_key =
Path.join([
"media",
Integer.to_string(datetime.year),
String.pad_leading(Integer.to_string(datetime.month), 2, "0"),
media.original_name
])
|> String.downcase()
Map.put(acc, source_key, Path.join("/", media.file_path))
end)
end
@spec post_path(map(), String.t() | nil) :: String.t()
def post_path(post, language_prefix)
when is_binary(language_prefix) and language_prefix != "" do
String.trim_trailing(language_prefix, "/") <> post_path(post, nil)
end
def post_path(post, ""), do: post_path(post, nil)
def post_path(post, nil) do
datetime = Persistence.from_unix_ms!(post.created_at)
Path.join([
"/",
Integer.to_string(datetime.year),
String.pad_leading(Integer.to_string(datetime.month), 2, "0"),
String.pad_leading(Integer.to_string(datetime.day), 2, "0"),
post.slug
]) <> "/"
end
@spec post_path(map(), String.t() | nil, String.t()) :: String.t()
def post_path(post, language, main_language) do
prefix = language_prefix(language, main_language)
post_path(post, prefix)
end
@spec link_contexts(String.t() | nil, String.t() | nil, :incoming | :outgoing, String.t()) :: [
map()
]
def link_contexts(_project_id, nil, _direction, _main_language), do: []
def link_contexts(project_id, post_id, :incoming, main_language) do
PostLinks.list_incoming_links(post_id)
|> Enum.map(&link_context(project_id, &1, :incoming, main_language))
|> Enum.reject(&is_nil/1)
end
def link_contexts(project_id, post_id, :outgoing, main_language) do
PostLinks.list_outgoing_links(post_id)
|> Enum.map(&link_context(project_id, &1, :outgoing, main_language))
|> Enum.reject(&is_nil/1)
end
defp link_context(_project_id, link, direction, main_language) do
linked_post_id =
case direction do
:incoming -> link.source_post_id
:outgoing -> link.target_post_id
end
case Repo.get(Post, linked_post_id) do
nil ->
nil
linked_post ->
%{
href: post_path(linked_post, nil),
title: linked_post.title,
display_slug: linked_post.slug,
language: normalize_language(linked_post.language, main_language)
}
end
end
@spec language_prefix(String.t() | nil, String.t()) :: String.t()
def language_prefix(language, main_language) when language == main_language, do: ""
def language_prefix(nil, _main_language), do: ""
def language_prefix(language, _main_language), do: "/#{language}"
@spec normalize_language(String.t() | nil, String.t()) :: String.t()
def normalize_language(nil, fallback), do: fallback
def normalize_language("", fallback), do: fallback
def normalize_language(language, _fallback) do
language
|> to_string()
|> String.downcase()
|> String.split("-", parts: 2)
|> hd()
end
end