chore: added more @spec

This commit is contained in:
2026-05-01 17:49:50 +02:00
parent abcae1dad7
commit 881056eb61
157 changed files with 6223 additions and 1647 deletions

View File

@@ -22,9 +22,23 @@ defmodule BDS.Scripting.Capabilities.AppShell do
command = string_or_nil(text)
case :os.type() do
{:unix, :darwin} -> match?({_output, 0}, System.cmd("pbcopy", [], input: command, stderr_to_stdout: true))
{:unix, _other} -> match?({_output, 0}, System.cmd("xclip", ["-selection", "clipboard"], input: command, stderr_to_stdout: true))
{:win32, _other} -> match?({_output, 0}, System.cmd("cmd", ["/c", "clip"], input: command, stderr_to_stdout: true))
{:unix, :darwin} ->
match?({_output, 0}, System.cmd("pbcopy", [], input: command, stderr_to_stdout: true))
{:unix, _other} ->
match?(
{_output, 0},
System.cmd("xclip", ["-selection", "clipboard"],
input: command,
stderr_to_stdout: true
)
)
{:win32, _other} ->
match?(
{_output, 0},
System.cmd("cmd", ["/c", "clip"], input: command, stderr_to_stdout: true)
)
end
end
rescue
@@ -94,7 +108,11 @@ defmodule BDS.Scripting.Capabilities.AppShell do
end
def set_preview_post_target(post_id) do
:persistent_term.put({BDS.Scripting.Capabilities, :preview_post_target}, string_or_nil(post_id))
:persistent_term.put(
{BDS.Scripting.Capabilities, :preview_post_target},
string_or_nil(post_id)
)
true
end

View File

@@ -98,7 +98,11 @@ defmodule BDS.Scripting.Capabilities.Bridges do
end
def detect_media_language(title, alt, caption, opts) do
text = Enum.join([string_or_nil(title) || "", string_or_nil(alt) || "", string_or_nil(caption) || ""], "\n")
text =
Enum.join(
[string_or_nil(title) || "", string_or_nil(alt) || "", string_or_nil(caption) || ""],
"\n"
)
case AI.detect_language(text, ai_opts(opts)) do
{:ok, %{language_code: language_code}} -> %{"success" => true, "language" => language_code}
@@ -125,7 +129,8 @@ defmodule BDS.Scripting.Capabilities.Bridges do
# --- Embeddings ---
def embedding_progress(project_id), do: project_id |> Embeddings.get_indexing_progress() |> unwrap_result()
def embedding_progress(project_id),
do: project_id |> Embeddings.get_indexing_progress() |> unwrap_result()
def find_similar(post_id, limit) do
post_id
@@ -148,9 +153,21 @@ defmodule BDS.Scripting.Capabilities.Bridges do
|> unwrap_result()
end
def find_duplicates(project_id), do: project_id |> Embeddings.find_duplicates() |> unwrap_result()
def dismiss_pair(post_id_a, post_id_b), do: atom_result(Embeddings.dismiss_duplicate_pair(string_or_nil(post_id_a) || "", string_or_nil(post_id_b) || ""), :ok)
def index_unindexed_posts(project_id), do: project_id |> Embeddings.index_unindexed() |> unwrap_result()
def find_duplicates(project_id),
do: project_id |> Embeddings.find_duplicates() |> unwrap_result()
def dismiss_pair(post_id_a, post_id_b),
do:
atom_result(
Embeddings.dismiss_duplicate_pair(
string_or_nil(post_id_a) || "",
string_or_nil(post_id_b) || ""
),
:ok
)
def index_unindexed_posts(project_id),
do: project_id |> Embeddings.index_unindexed() |> unwrap_result()
# --- Opt builders ---

View File

@@ -47,7 +47,10 @@ defmodule BDS.Scripting.Capabilities.Crud do
def list_scripts(project_id) do
Repo.all(
from(script in Script, where: script.project_id == ^project_id, order_by: [asc: script.created_at])
from(script in Script,
where: script.project_id == ^project_id,
order_by: [asc: script.created_at]
)
)
|> Enum.map(&sanitize/1)
end
@@ -68,7 +71,8 @@ defmodule BDS.Scripting.Capabilities.Crud do
def fetch_script(project_id, script_id) do
Repo.one(
from(script in Script,
where: script.project_id == ^project_id and script.id == ^(string_or_nil(script_id) || ""),
where:
script.project_id == ^project_id and script.id == ^(string_or_nil(script_id) || ""),
limit: 1
)
)
@@ -86,8 +90,11 @@ defmodule BDS.Scripting.Capabilities.Crud do
def update_template(project_id, template_id, attrs) do
case fetch_template(project_id, template_id) do
%Template{} -> Templates.update_template(template_id, normalize_map(attrs)) |> unwrap_result()
_other -> nil
%Template{} ->
Templates.update_template(template_id, normalize_map(attrs)) |> unwrap_result()
_other ->
nil
end
end
@@ -105,7 +112,10 @@ defmodule BDS.Scripting.Capabilities.Crud do
def list_templates(project_id) do
Repo.all(
from(template in Template, where: template.project_id == ^project_id, order_by: [asc: template.created_at])
from(template in Template,
where: template.project_id == ^project_id,
order_by: [asc: template.created_at]
)
)
|> Enum.map(&sanitize/1)
end
@@ -146,7 +156,9 @@ defmodule BDS.Scripting.Capabilities.Crud do
def fetch_template(project_id, template_id) do
Repo.one(
from(template in Template,
where: template.project_id == ^project_id and template.id == ^(string_or_nil(template_id) || ""),
where:
template.project_id == ^project_id and
template.id == ^(string_or_nil(template_id) || ""),
limit: 1
)
)
@@ -233,8 +245,14 @@ defmodule BDS.Scripting.Capabilities.Crud do
def merge_tags(project_id, source_tag_ids, target_tag_id) do
case fetch_tag(project_id, target_tag_id) do
%Tag{} -> atom_result(Tags.merge_tags(normalize_string_list(source_tag_ids), target_tag_id), :merged)
_other -> false
%Tag{} ->
atom_result(
Tags.merge_tags(normalize_string_list(source_tag_ids), target_tag_id),
:merged
)
_other ->
false
end
end

View File

@@ -21,8 +21,12 @@ defmodule BDS.Scripting.Capabilities.Media do
def update_media(project_id, media_id, attrs) do
case fetch_media(project_id, media_id) do
%MediaRecord{} -> Media.update_media(media_id, attrs |> normalize_map() |> normalize_media_attrs()) |> unwrap_result()
_other -> nil
%MediaRecord{} ->
Media.update_media(media_id, attrs |> normalize_map() |> normalize_media_attrs())
|> unwrap_result()
_other ->
nil
end
end
@@ -40,7 +44,10 @@ defmodule BDS.Scripting.Capabilities.Media do
def list_media(project_id) do
Repo.all(
from(media in MediaRecord, where: media.project_id == ^project_id, order_by: [asc: media.created_at])
from(media in MediaRecord,
where: media.project_id == ^project_id,
order_by: [asc: media.created_at]
)
)
|> Enum.map(&sanitize/1)
end
@@ -82,7 +89,11 @@ defmodule BDS.Scripting.Capabilities.Media do
def upsert_media_translation(project_id, media_id, language, attrs) do
case fetch_media(project_id, media_id) do
%MediaRecord{} ->
Media.upsert_media_translation(media_id, string_or_nil(language) || "", normalize_media_translation_attrs(normalize_map(attrs)))
Media.upsert_media_translation(
media_id,
string_or_nil(language) || "",
normalize_media_translation_attrs(normalize_map(attrs))
)
|> unwrap_result()
_other ->
@@ -117,7 +128,9 @@ defmodule BDS.Scripting.Capabilities.Media do
key = {datetime.year, datetime.month}
Map.update(acc, key, 1, &(&1 + 1))
end)
|> Enum.map(fn {{year, month}, count} -> %{"year" => year, "month" => month, "count" => count} end)
|> Enum.map(fn {{year, month}, count} ->
%{"year" => year, "month" => month, "count" => count}
end)
|> Enum.sort_by(fn row -> {-row["year"], -row["month"]} end)
end
@@ -131,7 +144,12 @@ defmodule BDS.Scripting.Capabilities.Media do
def media_tags(project_id), do: media_tags_with_counts(project_id) |> Enum.map(& &1["tag"])
def media_tags_with_counts(project_id) do
Repo.all(from(media in MediaRecord, where: media.project_id == ^project_id, order_by: [asc: media.created_at]))
Repo.all(
from(media in MediaRecord,
where: media.project_id == ^project_id,
order_by: [asc: media.created_at]
)
)
|> Enum.flat_map(&(&1.tags || []))
|> Enum.reduce(%{}, fn tag, acc -> Map.update(acc, tag, 1, &(&1 + 1)) end)
|> Enum.map(fn {tag, count} -> %{"tag" => tag, "count" => count} end)
@@ -174,7 +192,9 @@ defmodule BDS.Scripting.Capabilities.Media do
case Media.regenerate_thumbnails(media.id) do
{:ok, _media} ->
Media.thumbnail_paths(media)
|> Enum.map(fn {size, relative_path} -> {to_string(size), Path.join(project_path(project_id), relative_path)} end)
|> Enum.map(fn {size, relative_path} ->
{to_string(size), Path.join(project_path(project_id), relative_path)}
end)
|> Map.new()
{:error, _reason} ->
@@ -227,14 +247,40 @@ defmodule BDS.Scripting.Capabilities.Media do
tags = Map.get(media, "tags", [])
language = Map.get(media, "language")
matches_year = compare_optional(Map.get(filters, "year"), fn year -> created_at.year == integer_or_default(year, created_at.year) end)
matches_month = compare_optional(Map.get(filters, "month"), fn month -> created_at.month == integer_or_default(month, created_at.month) end)
matches_language = compare_optional(blank_to_nil(Map.get(filters, "language")), fn value -> language == value end)
matches_tags = compare_optional(Map.get(filters, "tags"), fn required_tags -> Enum.all?(normalize_string_list(required_tags), &(&1 in tags)) end)
matches_from = compare_optional(parse_datetime(Map.get(filters, "from") || Map.get(filters, "start_date")), fn from_dt -> DateTime.compare(created_at, from_dt) != :lt end)
matches_to = compare_optional(parse_datetime(Map.get(filters, "to") || Map.get(filters, "end_date")), fn to_dt -> DateTime.compare(created_at, to_dt) != :gt end)
matches_year =
compare_optional(Map.get(filters, "year"), fn year ->
created_at.year == integer_or_default(year, created_at.year)
end)
matches_year and matches_month and matches_language and matches_tags and matches_from and matches_to
matches_month =
compare_optional(Map.get(filters, "month"), fn month ->
created_at.month == integer_or_default(month, created_at.month)
end)
matches_language =
compare_optional(blank_to_nil(Map.get(filters, "language")), fn value ->
language == value
end)
matches_tags =
compare_optional(Map.get(filters, "tags"), fn required_tags ->
Enum.all?(normalize_string_list(required_tags), &(&1 in tags))
end)
matches_from =
compare_optional(
parse_datetime(Map.get(filters, "from") || Map.get(filters, "start_date")),
fn from_dt -> DateTime.compare(created_at, from_dt) != :lt end
)
matches_to =
compare_optional(
parse_datetime(Map.get(filters, "to") || Map.get(filters, "end_date")),
fn to_dt -> DateTime.compare(created_at, to_dt) != :gt end
)
matches_year and matches_month and matches_language and matches_tags and matches_from and
matches_to
end
def media_datetime(media) do
@@ -247,8 +293,11 @@ defmodule BDS.Scripting.Capabilities.Media do
_other -> DateTime.utc_now()
end
value when is_integer(value) -> DateTime.from_unix!(value, :millisecond)
_other -> DateTime.utc_now()
value when is_integer(value) ->
DateTime.from_unix!(value, :millisecond)
_other ->
DateTime.utc_now()
end
end
end

View File

@@ -22,8 +22,11 @@ defmodule BDS.Scripting.Capabilities.Posts do
def update_post(project_id, post_id, attrs) do
case fetch_post(project_id, post_id) do
%Post{} -> Posts.update_post(post_id, normalize_map(attrs)) |> unwrap_result(&post_payload/1)
_other -> nil
%Post{} ->
Posts.update_post(post_id, normalize_map(attrs)) |> unwrap_result(&post_payload/1)
_other ->
nil
end
end
@@ -42,7 +45,9 @@ defmodule BDS.Scripting.Capabilities.Posts do
end
def list_posts(project_id) do
Repo.all(from(post in Post, where: post.project_id == ^project_id, order_by: [asc: post.created_at]))
Repo.all(
from(post in Post, where: post.project_id == ^project_id, order_by: [asc: post.created_at])
)
|> Enum.map(&post_payload/1)
end
@@ -80,13 +85,19 @@ defmodule BDS.Scripting.Capabilities.Posts do
end
def generate_unique_post_slug(project_id, title, exclude_post_id) do
Posts.unique_slug_for_title(project_id, string_or_nil(title) || "", string_or_nil(exclude_post_id))
Posts.unique_slug_for_title(
project_id,
string_or_nil(title) || "",
string_or_nil(exclude_post_id)
)
end
def posts_by_status(project_id, status) do
normalized_status = string_or_nil(status) || ""
Repo.all(from(post in Post, where: post.project_id == ^project_id, order_by: [asc: post.created_at]))
Repo.all(
from(post in Post, where: post.project_id == ^project_id, order_by: [asc: post.created_at])
)
|> Enum.filter(&(to_string(&1.status) == normalized_status))
|> Enum.map(&post_payload/1)
end
@@ -143,8 +154,11 @@ defmodule BDS.Scripting.Capabilities.Posts do
def publish_post_translation(project_id, post_id, language) do
case fetch_post(project_id, post_id) do
%Post{} -> Posts.publish_post_translation(post_id, string_or_nil(language) || "") |> unwrap_result()
_other -> nil
%Post{} ->
Posts.publish_post_translation(post_id, string_or_nil(language) || "") |> unwrap_result()
_other ->
nil
end
end
@@ -174,7 +188,10 @@ defmodule BDS.Scripting.Capabilities.Posts do
def post_tags(project_id), do: names_with_counts(project_id, :tags) |> Enum.map(& &1["name"])
def post_tags_with_counts(project_id), do: names_with_counts(project_id, :tags)
def post_categories(project_id), do: names_with_counts(project_id, :categories) |> Enum.map(& &1["name"])
def post_categories(project_id),
do: names_with_counts(project_id, :categories) |> Enum.map(& &1["name"])
def post_categories_with_counts(project_id), do: names_with_counts(project_id, :categories)
def list_post_translations(project_id, post_id) do
@@ -209,9 +226,14 @@ defmodule BDS.Scripting.Capabilities.Posts do
def has_published_post_version(project_id, post_id) do
case fetch_post(project_id, post_id) do
%Post{status: :published} -> true
%Post{published_at: published_at, file_path: file_path} -> not is_nil(published_at) or file_path not in [nil, ""]
_other -> false
%Post{status: :published} ->
true
%Post{published_at: published_at, file_path: file_path} ->
not is_nil(published_at) or file_path not in [nil, ""]
_other ->
false
end
end

View File

@@ -10,9 +10,11 @@ defmodule BDS.Scripting.Capabilities.Projects do
alias BDS.Repo
alias BDS.Tags
def create_project(attrs), do: attrs |> normalize_map() |> ProjectsCtx.create_project() |> unwrap_result()
def create_project(attrs),
do: attrs |> normalize_map() |> ProjectsCtx.create_project() |> unwrap_result()
def delete_project(project_id), do: boolean_result(ProjectsCtx.delete_project(string_or_nil(project_id)))
def delete_project(project_id),
do: boolean_result(ProjectsCtx.delete_project(string_or_nil(project_id)))
def delete_project_with_data(project_id) do
case string_or_nil(project_id) && ProjectsCtx.get_project(string_or_nil(project_id)) do
@@ -113,8 +115,12 @@ defmodule BDS.Scripting.Capabilities.Projects do
normalized_name = string_or_nil(name) |> to_string() |> String.trim()
cond do
normalized_name == "" -> metadata_tags(project_id)
load_tag_by_name(project_id, normalized_name) -> metadata_tags(project_id)
normalized_name == "" ->
metadata_tags(project_id)
load_tag_by_name(project_id, normalized_name) ->
metadata_tags(project_id)
true ->
create_tag(project_id, %{"name" => normalized_name})
metadata_tags(project_id)

View File

@@ -46,7 +46,13 @@ defmodule BDS.Scripting.Capabilities.Util do
end
def normalize_input(list) when is_list(list) do
if Enum.all?(list, &match?({key, _value} when is_integer(key) or is_float(key) or is_binary(key) or is_atom(key), &1)) do
if Enum.all?(
list,
&match?(
{key, _value} when is_integer(key) or is_float(key) or is_binary(key) or is_atom(key),
&1
)
) do
normalized =
Map.new(list, fn {key, value} -> {normalize_input_key(key), normalize_input(value)} end)