defmodule MicrowavepropWeb.Api.V1.ContactController do @moduledoc "Read + create contacts (QSOs)." use Phoenix.Controller, formats: [:json] alias Microwaveprop.Accounts.Scope alias Microwaveprop.Radio alias Microwaveprop.Radio.Contact alias Microwaveprop.Repo alias MicrowavepropWeb.Api.ErrorJSON alias MicrowavepropWeb.Api.V1.ContactJSON plug :accepts, ["json"] action_fallback MicrowavepropWeb.Api.FallbackController @max_per_page 200 @spec index(Plug.Conn.t(), map()) :: Plug.Conn.t() def index(conn, params) do page = params |> Map.get("page", "1") |> parse_int(1) per_page = params |> Map.get("per_page", "50") |> parse_int(50) |> min(@max_per_page) |> max(1) search = params["search"] viewer = conn.assigns[:current_api_user] %{entries: entries, total_entries: total, total_pages: total_pages} = Radio.list_contacts( page: page, per_page: per_page, search: search, scope: Scope.for_user(viewer) ) json( conn, ContactJSON.index_paginated(%{ contacts: entries, viewer: viewer, page: page, per_page: per_page, total_entries: total, total_pages: total_pages }) ) end @spec show(Plug.Conn.t(), map()) :: Plug.Conn.t() def show(conn, %{"id" => id}) do viewer = conn.assigns[:current_api_user] case Repo.get(Contact, id) do nil -> ErrorJSON.send_problem(conn, 404, "not_found", "Contact not found.") %Contact{private: true, user_id: owner_id} = contact -> if owner_id && viewer && viewer.id == owner_id do json(conn, ContactJSON.show(%{contact: contact, viewer: viewer})) else ErrorJSON.send_problem(conn, 404, "not_found", "Contact not found.") end %Contact{} = contact -> json(conn, ContactJSON.show(%{contact: contact, viewer: viewer})) end end @spec create(Plug.Conn.t(), map()) :: Plug.Conn.t() def create(conn, params) do user = conn.assigns.current_api_user attrs = params |> Map.take( ~w(station1 station2 qso_timestamp mode band grid1 grid2 user_declared_prop_mode height1_ft height2_ft private notes) ) |> Map.put_new("submitter_email", user.email) case Radio.create_contact(attrs, user.id) do {:ok, contact} -> conn |> put_status(:created) |> json(ContactJSON.show(%{contact: contact, viewer: user})) {:error, %Ecto.Changeset{} = changeset} -> ErrorJSON.send_changeset(conn, changeset) {:error, :duplicate, existing} -> conn |> put_status(:conflict) |> json(%{ type: "about:blank", title: "duplicate_contact", status: 409, detail: "An equivalent contact already exists.", existing: ContactJSON.show(%{contact: existing, viewer: user}).data }) end end defp parse_int(value, fallback) when is_binary(value) do case Integer.parse(value) do {n, ""} when n >= 1 -> n _ -> fallback end end defp parse_int(_, fallback), do: fallback end