defmodule GitGudWeb.Plugs.ApContentNegotiation do
@moduledoc """
Detects ActivityPub clients by Accept header. When they ask for AP
JSON, we short-circuit to a dedicated controller; otherwise the
request flows through to the normal LiveView.
Activated content types:
* `application/activity+json`
* `application/ld+json` (any profile)
* `application/json` (only as a fallback — not officially AP but
tolerant to spec-loose clients)
"""
@behaviour Plug
import Plug.Conn
@ap_types ~w(
application/activity+json
application/ld+json
)
@impl true
def init(opts), do: opts
@impl true
def call(conn, _opts) do
if ap_requested?(conn) do
assign(conn, :ap_response?, true)
else
assign(conn, :ap_response?, false)
end
end
@doc "Pure helper exposed for controllers that decide manually."
def ap_requested?(conn) do
accept_header(conn)
|> Enum.any?(&ap_type?/1)
end
defp accept_header(conn) do
case get_req_header(conn, "accept") do
[] -> []
[h | _] -> String.split(h, ",", trim: true) |> Enum.map(&String.trim/1)
end
end
defp ap_type?(value) do
base = value |> String.split(";", parts: 2) |> List.first() |> String.downcase()
base in @ap_types
end
end
1.3 KiB · text
5af55d9