defmodule SyntropyWeb.Api.RecommendationController do use SyntropyWeb, :controller alias Syntropy.Persistence alias SyntropyWeb.Api.{ControllerHelpers, Listing, RecommendationJSON} @memory_scan_limit 1_000 @spec index(Plug.Conn.t(), map()) :: Plug.Conn.t() def index(conn, params) do case Listing.parse_opts(params, [:status, :kind, :q]) do {:ok, opts} -> page = recommendations_page(opts) json(conn, %{ data: Enum.map(page.entries, &RecommendationJSON.recommendation/1), meta: Listing.meta(page) }) {:error, :invalid_cursor} -> ControllerHelpers.invalid_request(conn, "Invalid cursor.", []) end end @spec show(Plug.Conn.t(), map()) :: Plug.Conn.t() def show(conn, %{"id" => recommendation_id}) do case Syntropy.recommendation(recommendation_id) || Persistence.get_recommendation(recommendation_id) do nil -> ControllerHelpers.not_found(conn, "Recommendation", recommendation_id) recommendation -> json(conn, %{data: RecommendationJSON.recommendation(recommendation)}) end end @spec approve(Plug.Conn.t(), map()) :: Plug.Conn.t() def approve(conn, %{"id" => recommendation_id}) do recommendation_id |> Syntropy.approve_recommendation() |> mutation_response(conn, recommendation_id) end @spec reject(Plug.Conn.t(), map()) :: Plug.Conn.t() def reject(conn, %{"id" => recommendation_id}) do recommendation_id |> Syntropy.reject_recommendation() |> mutation_response(conn, recommendation_id) end defp recommendations_page(opts) do if Persistence.enabled?() do Persistence.list_recommendations(opts) else @memory_scan_limit |> Syntropy.recent_recommendations() |> Listing.filter_recommendations(opts) |> Listing.paginate(opts, :created_at) end end defp mutation_response(result, conn, recommendation_id) do case result do {:ok, recommendation} -> json(conn, %{data: RecommendationJSON.recommendation(recommendation)}) {:error, :not_found} -> ControllerHelpers.not_found(conn, "Recommendation", recommendation_id) {:error, {:invalid_status, status}} -> ControllerHelpers.conflict( conn, "invalid_status", "Recommendation #{recommendation_id} is #{status} and can no longer change." ) {:error, _reason} -> ControllerHelpers.conflict( conn, "recommendation_not_applied", "Recommendation #{recommendation_id} could not be applied." ) end end end