From 3e7ee76fe2fe91c02e9171ed39213f545c7818a8 Mon Sep 17 00:00:00 2001 From: SomewhatDamaged Date: Fri, 1 May 2020 14:40:57 +1000 Subject: [PATCH] Api create image (#105) * added new method (POST) to /api/v1/json/images * Cleaned up debug * added require_authorization plug, fixed up issues with image_controller * make user do work * Fixed inefficient function use * added api fingerprinting * more robust * corrected holdover from merging files --- .../controllers/api/json/image_controller.ex | 43 ++++++++++++++++++ .../plugs/api_require_authorization_plug.ex | 45 +++++++++++++++++++ .../plugs/user_attribution_plug.ex | 10 ++++- lib/philomena_web/router.ex | 2 +- .../views/api/json/image_view.ex | 6 +++ 5 files changed, 104 insertions(+), 2 deletions(-) create mode 100755 lib/philomena_web/plugs/api_require_authorization_plug.ex diff --git a/lib/philomena_web/controllers/api/json/image_controller.ex b/lib/philomena_web/controllers/api/json/image_controller.ex index 534f0720..fa908f9d 100644 --- a/lib/philomena_web/controllers/api/json/image_controller.ex +++ b/lib/philomena_web/controllers/api/json/image_controller.ex @@ -2,10 +2,20 @@ defmodule PhilomenaWeb.Api.Json.ImageController do use PhilomenaWeb, :controller alias Philomena.Images.Image + alias Philomena.Images alias Philomena.Interactions alias Philomena.Repo + alias Philomena.Tags + alias Philomena.UserStatistics import Ecto.Query + plug :set_scraper_cache + plug PhilomenaWeb.ApiRequireAuthorizationPlug when action in [:create] + plug PhilomenaWeb.UserAttributionPlug when action in [:create] + + plug PhilomenaWeb.ScraperPlug, + [params_name: "image", params_key: "image"] when action in [:create] + def show(conn, %{"id" => id}) do user = conn.assigns.current_user @@ -27,4 +37,37 @@ defmodule PhilomenaWeb.Api.Json.ImageController do render(conn, "show.json", image: image, interactions: interactions) end end + + def create(conn, %{"image" => image_params}) do + user = conn.assigns.current_user + attributes = conn.assigns.attributes + + case Images.create_image(attributes, image_params) do + {:ok, %{image: image}} -> + spawn(fn -> + Images.repair_image(image) + end) + + # ImageProcessor.cast(image.id) + Images.reindex_image(image) + Tags.reindex_tags(image.added_tags) + UserStatistics.inc_stat(user, :uploads) + + render(conn, "show.json", image: image, interactions: []) + + {:error, :image, changeset, _} -> + conn + |> put_status(:bad_request) + |> render("error.json", changeset: changeset) + end + end + + defp set_scraper_cache(conn, _opts) do + params = + conn.params + |> Map.put_new("image", %{}) + |> Map.put("scraper_cache", conn.params["url"]) + + %{conn | params: params} + end end diff --git a/lib/philomena_web/plugs/api_require_authorization_plug.ex b/lib/philomena_web/plugs/api_require_authorization_plug.ex new file mode 100755 index 00000000..118a59c2 --- /dev/null +++ b/lib/philomena_web/plugs/api_require_authorization_plug.ex @@ -0,0 +1,45 @@ +defmodule PhilomenaWeb.ApiRequireAuthorizationPlug do + @moduledoc """ + This plug will force a 401 Unauthorized if no/invalid + API key provided and a 403 Forbidden if user is banned. + + ## Example + + plug PhilomenaWeb.ApiRequireAuthorizationPlug + """ + alias Phoenix.Controller + alias Plug.Conn + alias Philomena.Bans + + @doc false + @spec init(any()) :: any() + def init(opts), do: opts + + @doc false + @spec call(Conn.t(), any()) :: Conn.t() + def call(conn, _opts) do + user = conn.assigns.current_user + + conn + |> maybe_unauthorized(user) + |> maybe_forbidden(Bans.exists_for?(user, conn.remote_ip, "NOTAPI")) + end + + defp maybe_unauthorized(conn, nil) do + conn + |> Conn.put_status(:unauthorized) + |> Controller.text("") + |> Conn.halt() + end + + defp maybe_unauthorized(conn, _user), do: conn + + defp maybe_forbidden(conn, nil), do: conn + + defp maybe_forbidden(conn, _current_ban) do + conn + |> Conn.put_status(:forbidden) + |> Controller.text("") + |> Conn.halt() + end +end diff --git a/lib/philomena_web/plugs/user_attribution_plug.ex b/lib/philomena_web/plugs/user_attribution_plug.ex index f7daa0f1..806650f8 100644 --- a/lib/philomena_web/plugs/user_attribution_plug.ex +++ b/lib/philomena_web/plugs/user_attribution_plug.ex @@ -23,7 +23,7 @@ defmodule PhilomenaWeb.UserAttributionPlug do attributes = [ ip: remote_ip, - fingerprint: conn.cookies["_ses"], + fingerprint: fingerprint(conn, conn.path_info), referrer: conn.assigns.referrer, user: user, user_agent: user_agent(conn) @@ -39,4 +39,12 @@ defmodule PhilomenaWeb.UserAttributionPlug do _ -> nil end end + + defp fingerprint(conn, ["api" | _]) do + "a#{:erlang.crc32(user_agent(conn))}" + end + + defp fingerprint(conn, _) do + conn.cookies["_ses"] + end end diff --git a/lib/philomena_web/router.ex b/lib/philomena_web/router.ex index cf8c21bd..df6320a3 100644 --- a/lib/philomena_web/router.ex +++ b/lib/philomena_web/router.ex @@ -110,7 +110,7 @@ defmodule PhilomenaWeb.Router do resources "/featured", FeaturedController, only: [:show], singleton: true end - resources "/images", ImageController, only: [:show] + resources "/images", ImageController, only: [:show, :create] scope "/search", Search, as: :search do resources "/reverse", ReverseController, only: [:create] diff --git a/lib/philomena_web/views/api/json/image_view.ex b/lib/philomena_web/views/api/json/image_view.ex index 37ad1605..a722f7c9 100644 --- a/lib/philomena_web/views/api/json/image_view.ex +++ b/lib/philomena_web/views/api/json/image_view.ex @@ -83,6 +83,12 @@ defmodule PhilomenaWeb.Api.Json.ImageView do } end + def render("error.json", %{changeset: changeset}) do + %{ + errors: Ecto.Changeset.traverse_errors(changeset, &translate_error/1) + } + end + defp intensities(%{intensity: %{nw: nw, ne: ne, sw: sw, se: se}}), do: %{nw: nw, ne: ne, sw: sw, se: se}