defmodule PlausibleWeb.Plugins.API.Controllers.Goals do @moduledoc """ Controller for the Goal resource under Plugins API """ use PlausibleWeb, :plugins_api_controller operation(:create, operation_id: "Goal.GetOrCreate", summary: "Get or create Goal", request_body: {"Goal params", "application/json", Schemas.Goal.CreateRequest}, responses: %{ created: {"Goal", "application/json", Schemas.Goal.ListResponse}, unauthorized: {"Unauthorized", "application/json", Schemas.Unauthorized}, payment_required: {"Payment required", "application/json", Schemas.PaymentRequired}, unprocessable_entity: {"Unprocessable entity", "application/json", Schemas.UnprocessableEntity} } ) def create( %{private: %{open_api_spex: %{body_params: body_params}}} = conn, _params ) do site = conn.assigns.authorized_site goal_or_goals = case body_params do %{goals: goals} -> goals %{goal: _} = single_goal -> single_goal end case API.Goals.create(site, goal_or_goals) do {:ok, goals} -> location_headers = Enum.map(goals, &{"location", plugins_api_goals_url(conn, :get, &1.id)}) conn |> prepend_resp_headers(location_headers) |> put_view(Views.Goal) |> put_status(:created) |> render("index.json", goals: goals, authorized_site: site) {:error, :upgrade_required} -> payment_required(conn) {:error, changeset} -> Errors.error(conn, 422, changeset) end end operation(:index, summary: "Retrieve Goals", parameters: [ limit: [in: :query, type: :integer, description: "Maximum entries per page", example: 10], after: [ in: :query, type: :string, description: "Cursor value to seek after - generated internally" ], before: [ in: :query, type: :string, description: "Cursor value to seek before - generated internally" ] ], responses: %{ ok: {"Goals response", "application/json", Schemas.Goal.ListResponse}, unauthorized: {"Unauthorized", "application/json", Schemas.Unauthorized} } ) @spec index(Plug.Conn.t(), %{}) :: Plug.Conn.t() def index(conn, _params) do {:ok, pagination} = API.Goals.get_goals(conn.assigns.authorized_site, conn.query_params) conn |> put_view(Views.Goal) |> render("index.json", %{pagination: pagination}) end operation(:get, summary: "Retrieve Goal by ID", parameters: [ id: [ in: :path, type: :integer, description: "Goal ID", example: 123, required: true ] ], responses: %{ ok: {"Goal", "application/json", Schemas.Goal}, not_found: {"NotFound", "application/json", Schemas.NotFound}, unauthorized: {"Unauthorized", "application/json", Schemas.Unauthorized}, unprocessable_entity: {"Unprocessable entity", "application/json", Schemas.UnprocessableEntity} } ) @spec get(Plug.Conn.t(), map()) :: Plug.Conn.t() def get(%{private: %{open_api_spex: %{params: %{id: id}}}} = conn, _params) do site = conn.assigns.authorized_site case API.Goals.get(site, id) do nil -> conn |> put_view(Views.Error) |> put_status(:not_found) |> render("404.json") goal -> conn |> put_view(Views.Goal) |> put_status(:ok) |> render("goal.json", goal: goal, authorized_site: site) end end operation(:delete, summary: "Delete Goal by ID", parameters: [ id: [ in: :path, type: :integer, description: "Goal ID", example: 123, required: true ] ], responses: %{ no_content: {"NoContent", nil, nil}, unauthorized: {"Unauthorized", "application/json", Schemas.Unauthorized} } ) @spec delete(Plug.Conn.t(), map()) :: Plug.Conn.t() def delete(%{private: %{open_api_spex: %{params: %{id: id}}}} = conn, _params) do :ok = API.Goals.delete(conn.assigns.authorized_site, id) send_resp(conn, :no_content, "") end operation(:delete_bulk, operation_id: "Goal.DeleteBulk", summary: "Delete Goals in bulk", request_body: {"Goal params", "application/json", Schemas.Goal.DeleteBulkRequest}, responses: %{ no_content: {"NoContent", nil, nil}, unauthorized: {"Unauthorized", "application/json", Schemas.Unauthorized} } ) @spec delete_bulk(Plug.Conn.t(), map()) :: Plug.Conn.t() def delete_bulk( %{private: %{open_api_spex: %{body_params: %{goal_ids: goal_ids}}}} = conn, _params ) do :ok = API.Goals.delete(conn.assigns.authorized_site, goal_ids) send_resp(conn, :no_content, "") end defp payment_required(conn) do Errors.error( conn, 402, "#{Plausible.Billing.Feature.RevenueGoals.display_name()} is part of the Plausible Business plan. To get access to this feature, please upgrade your account." ) end end