143 lines
4.6 KiB
Elixir
143 lines
4.6 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 ->
|
|
source_key =
|
|
Path.join(["media" | year_month_path_parts(media.created_at)] ++ [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),
|
|
do: normalize_language_prefix(language_prefix) <> base_post_path(post)
|
|
|
|
@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 -> link_context_for_post(linked_post, main_language)
|
|
end
|
|
end
|
|
|
|
@spec link_context_for_post(map(), String.t()) :: map()
|
|
def link_context_for_post(linked_post, main_language) do
|
|
%{
|
|
href: post_path(linked_post, nil),
|
|
title: linked_post.title,
|
|
display_slug: linked_post.slug,
|
|
language: normalize_language(linked_post.language, main_language)
|
|
}
|
|
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
|
|
|
|
defp base_post_path(post) do
|
|
"/" <> Path.join(post_date_path_parts(post.created_at) ++ [post.slug]) <> "/"
|
|
end
|
|
|
|
defp post_date_path_parts(created_at) do
|
|
datetime = Persistence.from_unix_ms!(created_at)
|
|
year_month_path_parts(datetime) ++ [BDS.Strings.pad2(datetime.day)]
|
|
end
|
|
|
|
defp year_month_path_parts(created_at) when is_integer(created_at) do
|
|
created_at
|
|
|> Persistence.from_unix_ms!()
|
|
|> year_month_path_parts()
|
|
end
|
|
|
|
defp year_month_path_parts(%DateTime{} = datetime) do
|
|
[Integer.to_string(datetime.year), BDS.Strings.pad2(datetime.month)]
|
|
end
|
|
|
|
defp normalize_language_prefix(prefix) when is_binary(prefix) and prefix != "",
|
|
do: String.trim_trailing(prefix, "/")
|
|
|
|
defp normalize_language_prefix(_prefix), do: ""
|
|
end
|