113 lines
3.2 KiB
Elixir
113 lines
3.2 KiB
Elixir
defmodule BDS.MCP.Resources do
|
|
@moduledoc false
|
|
|
|
alias BDS.MCP.ProposalStore
|
|
alias BDS.MCP.Queries
|
|
alias BDS.MCP.Util
|
|
alias BDS.Media.Media, as: MediaAsset
|
|
alias BDS.Metadata
|
|
alias BDS.Posts.Post
|
|
alias BDS.Repo
|
|
alias BDS.Search
|
|
alias BDS.Tags
|
|
|
|
@typedoc "Resource descriptor returned by `list/0`."
|
|
@type descriptor :: %{name: String.t(), uri: String.t()}
|
|
|
|
@spec list() :: [descriptor()]
|
|
def list do
|
|
[
|
|
%{name: "posts", uri: "bds://posts"},
|
|
%{name: "media", uri: "bds://media"},
|
|
%{name: "tags", uri: "bds://tags"},
|
|
%{name: "categories", uri: "bds://categories"}
|
|
]
|
|
end
|
|
|
|
@spec read(String.t()) :: {:ok, term()} | {:error, term()}
|
|
def read(uri) when is_binary(uri) do
|
|
ProposalStore.ensure_started()
|
|
|
|
case URI.parse(uri) do
|
|
%URI{scheme: "bds", host: "posts", path: nil} -> {:ok, posts_resource(0)}
|
|
%URI{scheme: "bds", host: "media", path: nil} -> {:ok, media_resource(0)}
|
|
%URI{scheme: "bds", host: "tags", path: nil} -> {:ok, tags_resource()}
|
|
%URI{scheme: "bds", host: "categories", path: nil} -> {:ok, categories_resource()}
|
|
%URI{scheme: "bds", host: "posts", path: "/" <> id} -> read_post_resource(id)
|
|
%URI{scheme: "bds", host: "media", path: "/" <> id} -> read_media_resource(id)
|
|
_other -> {:error, :not_found}
|
|
end
|
|
end
|
|
|
|
defp posts_resource(offset) do
|
|
project = Queries.active_project!()
|
|
page_size = Queries.page_size()
|
|
{:ok, result} = Search.search_posts(project.id, "", %{offset: offset, limit: page_size})
|
|
|
|
%{
|
|
"items" => Enum.map(result.posts, &Queries.post_summary/1),
|
|
"total" => result.total,
|
|
"offset" => result.offset,
|
|
"limit" => result.limit,
|
|
"has_more" => result.offset + result.limit < result.total
|
|
}
|
|
end
|
|
|
|
defp media_resource(offset) do
|
|
project = Queries.active_project!()
|
|
page_size = Queries.page_size()
|
|
{:ok, result} = Search.search_media(project.id, "", %{offset: offset, limit: page_size})
|
|
|
|
%{
|
|
"items" => Enum.map(result.media, &Util.sanitize/1),
|
|
"total" => result.total,
|
|
"offset" => result.offset,
|
|
"limit" => result.limit,
|
|
"has_more" => result.offset + result.limit < result.total
|
|
}
|
|
end
|
|
|
|
defp tags_resource do
|
|
project = Queries.active_project!()
|
|
tags = Tags.list_tags(project.id)
|
|
|
|
%{
|
|
"items" =>
|
|
Enum.map(tags, fn tag ->
|
|
%{
|
|
"id" => tag.id,
|
|
"name" => tag.name,
|
|
"color" => tag.color,
|
|
"post_count" => Queries.tag_post_count(project.id, tag.name)
|
|
}
|
|
end)
|
|
}
|
|
end
|
|
|
|
defp categories_resource do
|
|
project = Queries.active_project!()
|
|
{:ok, metadata} = Metadata.get_project_metadata(project.id)
|
|
|
|
%{
|
|
"items" =>
|
|
Enum.map(metadata.categories, fn category ->
|
|
%{"name" => category, "post_count" => Queries.category_post_count(project.id, category)}
|
|
end)
|
|
}
|
|
end
|
|
|
|
defp read_post_resource(id) do
|
|
case Repo.get(Post, id) do
|
|
%Post{} = post -> {:ok, Queries.post_detail(post)}
|
|
nil -> {:error, :not_found}
|
|
end
|
|
end
|
|
|
|
defp read_media_resource(id) do
|
|
case Repo.get(MediaAsset, id) do
|
|
%MediaAsset{} = media -> {:ok, Util.sanitize(media)}
|
|
nil -> {:error, :not_found}
|
|
end
|
|
end
|
|
end
|