cat-bookmarker/bookmarker/lib/bookmarker_web/controllers/api_controller.ex

144 lines
4.5 KiB
Elixir

defmodule BookmarkerWeb.APIController do
use BookmarkerWeb, :controller
alias Bookmarker.{Repo, Bookmark}
import Ecto.Query
@doc """
A quicker way to return a JSON object with the key "error" and the given
message
"""
defp error(conn, message) do
json(conn, %{"error" => message})
end
@doc """
Takes a Bookmark struct and removes all the bits that aren't easily turned
into JSON
"""
defp sanitized_bookmark(bookmark) do
%{
id: bookmark.id,
creator: bookmark.creator,
category: bookmark.category,
remote_id: bookmark.remote_id,
notes: bookmark.notes
}
end
@doc """
POST /api/v1/bookmark - Create a new bookmark. This just builds a
%Bookmark{} and then inserts it into the database, returning the ID of the
newly created resource.
"""
def create(conn, _params) do
record = %Bookmark{
creator: conn.assigns[:user_id],
category: conn.body_params["category"],
remote_id: conn.body_params["remote_id"],
notes: conn.body_params["notes"]
}
{:ok, result} = Repo.insert(record)
# Return the new bookmark's ID
json(conn, %{
id: result.id
})
end
@doc """
GET /api/v1/bookmark - Returns a list of bookmarks created by the user.
Repo.all returns a list of, in this case, %Bookmark{} results, so each
of these must be sanitized with Enum.map/2 and our private function for
sanitizing the structs.
"""
def index(conn, _params) do
records = Repo.all(from b in Bookmark,
where: b.creator == ^conn.assigns[:user_id],
select: b)
|> Enum.map(fn b -> sanitized_bookmark(b) end)
json(conn, records)
end
@doc """
GET /api/v1/bookmark/single/:id - Returns a single bookmark by ID. If
Repo.get/2 returns `nil` here, then the bookmark can't be found and we
return 404. Otherwise, we sanitize the struct and return it as a JSON
string.
If the bookmark doesn't belong to the user, then the server returns 403.
"""
def show(conn, %{"id" => id}) do
case Repo.get(Bookmark, id) do
nil -> conn
|> put_status(404)
|> error("Bookmark not found")
bookmark ->
if bookmark.creator == conn.assigns[:user_id] do
conn
|> json(sanitized_bookmark(bookmark))
else
conn
|> put_status(403)
|> error("You do not have access to this bookmark")
end
end
end
@doc """
DELETE /api/v1/bookmark/:id - Gets the bookmark and then deletes it from
the database. If the bookmark doesn't belong to the user trying to delete
it, then the server returns 403.
This assumes that there won't be any malformed requests, which is not
ideal, especially if we're not the only ones developing clients
"""
def delete(conn, %{"id" => id}) do
case Repo.get(Bookmark, id) do
nil ->
conn
|> put_status(404)
|> error("Bookmark not found")
bookmark ->
if bookmark.creator == conn.assigns[:user_id] do
Repo.delete!(bookmark)
json(conn, %{"id" => bookmark.id})
else
conn
|> put_status(403)
|> error("Cannot delete others' bookmarks")
end
end
end
@doc """
GET /api/v1/bookmark/category/:category - Get all of the given category
"""
def index_category(conn, %{"category" => category}) do
user_id = conn.assigns[:user_id]
records = Repo.all(from b in Bookmark,
where: b.creator == ^user_id and b.category == ^category,
select: b)
|> Enum.map(fn b -> sanitized_bookmark(b) end)
json(conn, records)
end
@doc """
GET /api/v1/bookmark/categories - Returns a list of all categories used in
bookmarks by a user. To do this, we fetch all records, select only their
categories and then deduplicate the list.
"""
def index_categories(conn, _params) do
user_id = conn.assigns.user_id
categories = Repo.all(from b in Bookmark,
where: b.creator == ^user_id,
select: b.category)
|> Enum.uniq()
json(conn, categories)
end
end