defmodule GitGudWeb.Api.Mobile.BadgeController do
@moduledoc """
A repository's badges, for `gg badges`: every badge it has, what each
says right now, and the Markdown and HTML that embed it.
GET /api/mobile/v1/repos/:owner/:name/badges
?style=dot&corners=square&scale=2x&gg=true&theme=forest&format=png
The query takes the badge sheet's options, each optional, and the
embeds are built with them. The answer is `GitGudWeb.BadgeCatalog`'s,
the same the badge sheet's README block uses, so a README a person
built on the page and one an agent built with the CLI say the same
thing. `defaults` lists the badges the README block starts with.
`repo:read`: a badge says nothing the repository's pages don't.
"""
use GitGudWeb, :controller
import GitGudWeb.Api.Mobile.Helpers
alias GitGud.Badges.Spec
alias GitGudWeb.Api.Mobile.Auth
alias GitGudWeb.BadgeCatalog
def index(conn, %{"owner" => owner, "name" => name} = params) do
with {:ok, user} <- Auth.require_scope(conn, "repo:read"),
{:ok, repo} <- fetch_repo(conn, user, owner, name),
{:ok, options} <- options(conn, params) do
handle = BadgeCatalog.handle(repo)
items = BadgeCatalog.items(repo)
keys = Enum.map(items, & &1.key)
json(conn, %{
"repository" => "#{handle}/#{repo.name}",
"options" => %{
"style" => options.style,
"corners" => options.corners,
"scale" => options.scale,
"gg" => options.gg,
"theme" => options.theme,
"format" => options.format
},
"defaults" => Enum.filter(BadgeCatalog.readme_defaults(), &(&1 in keys)),
"badges" =>
Enum.map(items, fn item ->
spec = BadgeCatalog.spec(options, item.key, options.theme, options.format)
badge(item, BadgeCatalog.embed(repo, handle, spec))
end)
})
else
{:error, conn} -> conn
end
end
defp badge(item, embed) do
{label, value, status} =
case item.content do
:mark -> {"GitGud", nil, nil}
%{label: label, value: value, slot: slot} -> {label, value, slot}
end
%{
"key" => item.key,
"kind" => item.kind,
"group" => item.group,
"title" => item.title,
"hint" => item.hint,
"label" => label,
"value" => value,
"status" => status,
"url" => embed.url,
"dark_url" => embed.dark_url,
"light_url" => embed.light_url,
"link" => embed.link,
"alt" => embed.alt,
"markdown" => embed.markdown,
"html" => embed.html
}
end
# Each option is checked against what the badge URLs accept, and a bad
# one says what would have been.
defp options(conn, params) do
checks = [
{:style, params["style"], Spec.styles()},
{:corners, params["corners"], Spec.corners()},
{:scale, params["scale"], Spec.scales()},
{:theme, params["theme"], Spec.themes()},
{:format, params["format"], Spec.formats()}
]
Enum.reduce_while(checks, {:ok, %Spec{}}, fn
{_field, nil, _allowed}, acc ->
{:cont, acc}
{field, value, allowed}, {:ok, spec} ->
if value in allowed,
do: {:cont, {:ok, Map.put(spec, field, value)}},
else:
{:halt,
{:error,
send_error(conn, 422, "#{field} must be one of #{Enum.join(allowed, ", ")}")}}
end)
|> case do
{:ok, spec} -> {:ok, %{spec | gg: params["gg"] in ["true", "1", "yes"]}}
error -> error
end
end
end
neiam
/gitgud
Git Gud
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
1
Log in to mark this repository.
3.5 KiB · text
History
b868907