lib/yousign/api/documents.ex

defmodule Yousign.API.Documents do
  import Yousign.Request

  alias Yousign.Document
  alias Multipart.Part
  alias Yousign.DocumentInput

  @doc """
    Gets a single document by its id

    ## Examples

        iex> Yousign.API.Documents.get("123")
        {:ok, %{"data" => %{"id" => "123", "name" => "test"}}}

        iex> Yousign.API.Documents.get("invalid")
        {:error, 404}
  """
  @spec get(String.t(), String.t()) :: {:error, any()} | {:ok, any()}
  def get(signature_request_id, id) do
    make_request(:get, "signature_requests/#{signature_request_id}/documents/#{id}")
  end

  @doc """
  List all documents in a signature request

  ## Examples

      iex> Yousign.API.Documents.list("123")
      {:ok, %{"data" => [], "meta" => %{"pagination" => %{"total" => 0}}}}

      iex> Yousign.API.Documents.list("123")
      {:ok, %{"data" => [%{"id" => "123", "name" => "test"}], "meta" => %{"pagination" => %{"total" => 1}}}}
  """
  @spec list(String.t()) :: {:error, any()} | {:ok, any()}
  def list(signature_request_id) do
    make_request(:get, "signature_requests/#{signature_request_id}/documents")
  end

  @doc """
  Creates a new document
  """
  @spec create(%DocumentInput{}, String.t() | boolean()) :: {:error, any()} | {:ok, %Document{}}
  def create(body, filename \\ true) do
    {:ok, path} = base64_to_file(body.file)

    body =
      Multipart.new()
      |> Multipart.add_part(Part.text_field(Atom.to_string(Map.get(body, :nature, nil)), :nature))
      |> Multipart.add_part(
        Part.text_field(to_string(Map.get(body, :parse_anchors, false)), :parse_anchors)
      )
      |> Multipart.add_part(Part.file_field(path, :file, filename: filename))

    case make_multipart_request(:post, "documents", body, 201) do
      {:ok, data} ->
        File.rm!(path)
        {:ok, data}

      {:error, error} ->
        File.rm!(path)
        {:error, error}
    end
  end

  @doc """
  Creates a new document and adds it to the given signature request
  """
  @spec add_to_signature_request(String.t(), %DocumentInput{}, String.t() | boolean()) ::
          {:error, any()} | {:ok, %Document{}}
  def add_to_signature_request(signature_request_id, body, filename \\ true) do
    {:ok, path} = base64_to_file(body.file)

    body =
      Multipart.new()
      |> Multipart.add_part(Part.text_field(Atom.to_string(Map.get(body, :nature, nil)), :nature))
      |> Multipart.add_part(
        Part.text_field(to_string(Map.get(body, :parse_anchors, false)), :parse_anchors)
      )
      |> Multipart.add_part(Part.file_field(path, :file, filename: filename))

    case make_multipart_request(
           :post,
           "signature_requests/#{signature_request_id}/documents",
           body,
           201
         ) do
      {:ok, data} ->
        File.rm!(path)
        {:ok, data}

      {:error, error} ->
        File.rm!(path)
        {:error, error}
    end
  end

  @doc """
  Downloads all the documents attached to a signature request

  Version Options:
    - :completed: downloads the completed version of the documents
    - :current: downloads the current version of the documents

  Defaults to :current
  """
  @spec download(String.t(), atom()) :: {:error, any()} | {:ok, any()}
  def download(signature_request_id, version \\ :current)

  def download(signature_request_id, :completed) do
    make_request(
      :get,
      "signature_requests/#{signature_request_id}/documents/download?version=completed"
    )
  end

  def download(signature_request_id, :current) do
    make_request(
      :get,
      "signature_requests/#{signature_request_id}/documents/download?version=current"
    )
  end

  @spec base64_to_file(String.t()) :: {:error, any()} | {:ok, String.t()}
  defp base64_to_file(encoded_string) do
    with {:ok, data} <- Base.decode64(encoded_string),
         {:ok, path} <-
           Temp.path(prefix: "yousign_ex_temp", suffix: ".pdf"),
         {:ok, file} <- File.open(path, [:write, :binary]),
         :ok <- IO.binwrite(file, data),
         :ok <- File.close(file) do
      {:ok, path}
    end
  end
end