144 lines
4.5 KiB
Elixir
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
|