A bit off-topic, sorry, but since with
returns any unmatched expression anyway
iex(1)> with {:ok, "a"} <- {:error, "b"}, do: :ok # no need for `else` block
{:error, "b"}
your controller actions can be simplified a bit
def show(conn, %{"id" => id}) do
document = DocManager.get_document!(id)
# {:ok, user_id} returned if token is valid and carries the user_id,
# otherwise {:error, "note authorized" } is returned.
# Users are allowed to read their own docs and public docs
with {:ok, user_id} <- Token.user_id_from_header(conn),
true <- document.attributes["public"] or user_id == document.author_id,
do: render(conn, "show.json", document: document)
end
def show_public(conn, %{"id" => id}) do
document = DocManager.get_document!(id)
if document.attributes["public"] do
render(conn, "show.json", document: document)
else
{:error, "Cannot display document"}
end
end
Assuming attributes
is a map, I would also separate true <- document.attributes["public"] or user_id == document.author_id
into helper functions for better errors like
defp public_or_author(%{attributes: %{"public" => true}})
defp public?(%{attributes: %{"public" => true}}, do: :yep
defp public?(%{attributes: %{"public" => false}}, do: {:error, :not_public}
defp author?(_id, %{author_id: _id}), do: :yep
defp author?(_id, %{author_id: _author_id}), do: {:error, :not_author}
so that the with
block becomes
with {:ok, user_id} <- Token.user_id_from_header(conn),
:yep <- public?(document),
:yep <- author?(user_id, document),
do: render(conn, "show.json", document: document)