defmodule ClacksWeb.OutboxController do use ClacksWeb, :controller alias Clacks.{Repo, Actor, Activity} import Ecto.Query @context "https://www.w3.org/ns/activitystreams" @outbox_types ["Create", "Announce"] plug :get_actor defp get_actor(%Plug.Conn{path_params: %{"nickname" => nickname}} = conn, _opts) do case Actor.get_by_nickname(nickname) do nil -> conn |> put_status(404) %Actor{local: false} -> conn |> put_status(404) actor -> assign(conn, :actor, actor) end end def outbox(conn, params) when params == %{} do actor = conn.assigns[:actor] activities = Repo.all(outbox_query(params, actor)) data = %{ "@context" => @context, "type" => "OrderedCollection", "id" => current_url(conn, %{}), "first" => outbox_page(conn, params, activities) } conn |> put_resp_header("content-type", "application/activity+json") |> json(data) end def outbox(conn, params) do actor = conn.assigns[:actor] activities = Repo.all(outbox_query(params, actor)) data = outbox_page(conn, params, activities) |> Map.put("@context", @context) conn |> put_resp_header("content-type", "application/activity+json") |> json(data) end defp outbox_query(params, %Actor{ap_id: ap_id}) do Activity |> where([a], a.actor == ^ap_id) |> where([a], fragment("?->>'type'", a.data) in @outbox_types) |> Clacks.Paginator.paginate(params) |> limit(^Map.get(params, "limit", 20)) end defp outbox_page(conn, pagination_params, activities) do last_id = List.last(activities).id %{ "type" => "OrderedColletionPage", "partOf" => current_url(conn, %{}), "id" => current_url(conn, pagination_params), "next" => current_url(conn, %{max_id: last_id}), "orderedItems" => Enum.map(activities, & &1.data) } end end