From 12fb45170ce4a77a8cac1e867b8945752e8cf28a Mon Sep 17 00:00:00 2001 From: "byte[]" Date: Tue, 3 Dec 2019 19:50:23 -0500 Subject: [PATCH] api changes --- .../controllers/api/json/image_controller.ex | 12 ++++ .../api/json/search/reverse_controller.ex | 24 ++++++++ .../controllers/api/json/search_controller.ex | 33 +++++++++++ .../api/{ => rss}/watched_controller.ex | 2 +- .../controllers/search/reverse_controller.ex | 51 +---------------- lib/philomena_web/image_json.ex | 38 +++++++++++++ lib/philomena_web/image_loader.ex | 3 +- lib/philomena_web/image_reverse.ex | 56 +++++++++++++++++++ lib/philomena_web/router.ex | 27 ++++++--- .../api/{ => rss}/watched/index.rss.eex | 0 .../views/api/{ => rss}/watched_view.ex | 2 +- 11 files changed, 187 insertions(+), 61 deletions(-) create mode 100644 lib/philomena_web/controllers/api/json/image_controller.ex create mode 100644 lib/philomena_web/controllers/api/json/search/reverse_controller.ex create mode 100644 lib/philomena_web/controllers/api/json/search_controller.ex rename lib/philomena_web/controllers/api/{ => rss}/watched_controller.ex (92%) create mode 100644 lib/philomena_web/image_json.ex create mode 100644 lib/philomena_web/image_reverse.ex rename lib/philomena_web/templates/api/{ => rss}/watched/index.rss.eex (100%) rename lib/philomena_web/views/api/{ => rss}/watched_view.ex (83%) diff --git a/lib/philomena_web/controllers/api/json/image_controller.ex b/lib/philomena_web/controllers/api/json/image_controller.ex new file mode 100644 index 00000000..c68c72e2 --- /dev/null +++ b/lib/philomena_web/controllers/api/json/image_controller.ex @@ -0,0 +1,12 @@ +defmodule PhilomenaWeb.Api.Json.ImageController do + use PhilomenaWeb, :controller + + alias PhilomenaWeb.ImageJson + alias Philomena.Images.Image + + plug :load_and_authorize_resource, model: Image, only: [:show], preload: [:tags, :user] + + def show(conn, _params) do + json(conn, %{image: ImageJson.as_json(conn, conn.assigns.image)}) + end +end \ No newline at end of file diff --git a/lib/philomena_web/controllers/api/json/search/reverse_controller.ex b/lib/philomena_web/controllers/api/json/search/reverse_controller.ex new file mode 100644 index 00000000..eb3be941 --- /dev/null +++ b/lib/philomena_web/controllers/api/json/search/reverse_controller.ex @@ -0,0 +1,24 @@ +defmodule PhilomenaWeb.Api.Json.Search.ReverseController do + use PhilomenaWeb, :controller + + alias PhilomenaWeb.ImageReverse + + plug :set_scraper_cache + plug PhilomenaWeb.ScraperPlug, [params_key: "image", params_name: "image"] + + def create(conn, %{"image" => image_params}) do + images = ImageReverse.images(image_params) + + conn + |> json(%{images: images}) + end + + defp set_scraper_cache(conn, _opts) do + params = + conn.params + |> Map.put("image", %{}) + |> Map.put("scraper_cache", conn.params["url"]) + + %{conn | params: params} + end +end \ No newline at end of file diff --git a/lib/philomena_web/controllers/api/json/search_controller.ex b/lib/philomena_web/controllers/api/json/search_controller.ex new file mode 100644 index 00000000..adf0eea7 --- /dev/null +++ b/lib/philomena_web/controllers/api/json/search_controller.ex @@ -0,0 +1,33 @@ +defmodule PhilomenaWeb.Api.Json.SearchController do + use PhilomenaWeb, :controller + + alias PhilomenaWeb.ImageLoader + alias PhilomenaWeb.ImageJson + alias Philomena.ImageSorter + alias Philomena.Interactions + alias Philomena.Images.Image + import Ecto.Query + + def index(conn, params) do + queryable = Image |> preload([:tags, :user]) + user = conn.assigns.current_user + sort = ImageSorter.parse_sort(params) + + case ImageLoader.search_string(conn, params["q"], sorts: sort.sorts, queries: sort.queries, queryable: queryable) do + {:ok, images} -> + interactions = + Interactions.user_interactions(images, user) + + conn + |> json(%{ + images: Enum.map(images, &ImageJson.as_json(conn, &1)), + interactions: interactions + }) + + {:error, msg} -> + conn + |> Plug.Conn.put_status(:bad_request) + |> json(%{error: msg}) + end + end +end \ No newline at end of file diff --git a/lib/philomena_web/controllers/api/watched_controller.ex b/lib/philomena_web/controllers/api/rss/watched_controller.ex similarity index 92% rename from lib/philomena_web/controllers/api/watched_controller.ex rename to lib/philomena_web/controllers/api/rss/watched_controller.ex index 75702e58..916b84e6 100644 --- a/lib/philomena_web/controllers/api/watched_controller.ex +++ b/lib/philomena_web/controllers/api/rss/watched_controller.ex @@ -1,4 +1,4 @@ -defmodule PhilomenaWeb.Api.WatchedController do +defmodule PhilomenaWeb.Api.Rss.WatchedController do use PhilomenaWeb, :controller alias Philomena.Images.{Image, Query} diff --git a/lib/philomena_web/controllers/search/reverse_controller.ex b/lib/philomena_web/controllers/search/reverse_controller.ex index 56c56344..3ab6d4e7 100644 --- a/lib/philomena_web/controllers/search/reverse_controller.ex +++ b/lib/philomena_web/controllers/search/reverse_controller.ex @@ -1,10 +1,7 @@ defmodule PhilomenaWeb.Search.ReverseController do use PhilomenaWeb, :controller - alias Philomena.Processors - alias Philomena.DuplicateReports - alias Philomena.Repo - import Ecto.Query + alias PhilomenaWeb.ImageReverse plug PhilomenaWeb.ScraperPlug, [params_key: "image", params_name: "image"] when action in [:create] @@ -13,53 +10,9 @@ defmodule PhilomenaWeb.Search.ReverseController do end def create(conn, %{"image" => image_params}) do - images = - image_params["image"].path - |> mime() - |> analyze() - |> intensities() - |> case do - :error -> - [] - - {analysis, intensities} -> - {width, height} = analysis.dimensions - aspect = width / height - dist = normalize_dist(image_params) - - DuplicateReports.duplicates_of(intensities, aspect, dist, dist) - |> preload(:tags) - |> Repo.all() - end + images = ImageReverse.images(image_params) conn |> render("index.html", images: images) end - - defp mime(file) do - {:ok, mime} = Philomena.Mime.file(file) - - {mime, file} - end - - defp analyze({mime, file}) do - case Processors.analyzers(mime) do - nil -> :error - a -> {a.analyze(file), mime, file} - end - end - - defp intensities(:error), do: :error - defp intensities({analysis, mime, file}) do - {analysis, Processors.processors(mime).intensities(analysis, file)} - end - - # The distance metric is taxicab distance, not Euclidean, - # because this is more efficient to index. - defp normalize_dist(%{"distance" => distance}) do - distance - |> String.to_float() - |> max(0.01) - |> min(1.0) - end end \ No newline at end of file diff --git a/lib/philomena_web/image_json.ex b/lib/philomena_web/image_json.ex new file mode 100644 index 00000000..edc86ba5 --- /dev/null +++ b/lib/philomena_web/image_json.ex @@ -0,0 +1,38 @@ +defmodule PhilomenaWeb.ImageJson do + alias PhilomenaWeb.ImageView + + def as_json(conn, image) do + %{ + id: image.id, + created_at: image.created_at, + updated_at: image.updated_at, + first_seen_at: image.first_seen_at, + width: image.image_width, + height: image.image_height, + mime_type: image.image_mime_type, + format: image.image_format, + aspect_ratio: image.image_aspect_ratio, + name: image.image_name, + sha512_hash: image.image_sha512_hash, + orig_sha512_hash: image.image_orig_sha512_hash, + tags: Enum.map(image.tags, & &1.name), + tag_ids: Enum.map(image.tags, & &1.id), + uploader: if(!!image.user and !image.anonymous, do: image.user.name), + uploader_id: if(!!image.user and !image.anonymous, do: image.user.id), + wilson_score: Philomena.Images.Elasticsearch.wilson_score(image), + score: image.score, + upvotes: image.upvotes_count, + downvotes: image.downvotes_count, + faves: image.faves_count, + comment_count: image.comments_count, + tag_count: length(image.tags), + description: image.description, + source_url: image.source_url, + view_url: ImageView.pretty_url(image, false, false), + representations: ImageView.thumb_urls(image, false), + spoilered: ImageView.filter_or_spoiler_hits?(conn, image), + thumbnails_generated: image.thumbnails_generated, + processed: image.processed + } + end +end \ No newline at end of file diff --git a/lib/philomena_web/image_loader.ex b/lib/philomena_web/image_loader.ex index 4977bc9c..d19f48b4 100644 --- a/lib/philomena_web/image_loader.ex +++ b/lib/philomena_web/image_loader.ex @@ -17,6 +17,7 @@ defmodule PhilomenaWeb.ImageLoader do sort_queries = Keyword.get(options, :queries, []) sort_sorts = Keyword.get(options, :sorts, [%{created_at: :desc}]) pagination = Keyword.get(options, :pagination, conn.assigns.image_pagination) + queryable = Keyword.get(options, :queryable, Image |> preload(:tags)) user = conn.assigns.current_user filter = conn.assigns.compiled_filter @@ -33,7 +34,7 @@ defmodule PhilomenaWeb.ImageLoader do sort: sort_sorts }, pagination, - Image |> preload(:tags) + queryable ) end diff --git a/lib/philomena_web/image_reverse.ex b/lib/philomena_web/image_reverse.ex new file mode 100644 index 00000000..bbbcc3b2 --- /dev/null +++ b/lib/philomena_web/image_reverse.ex @@ -0,0 +1,56 @@ +defmodule PhilomenaWeb.ImageReverse do + alias Philomena.Processors + alias Philomena.DuplicateReports + alias Philomena.Repo + import Ecto.Query + + def images(image_params) do + image_params + |> Map.get("image") + |> Map.get(:path) + |> mime() + |> analyze() + |> intensities() + |> case do + :error -> + [] + + {analysis, intensities} -> + {width, height} = analysis.dimensions + aspect = width / height + dist = normalize_dist(image_params) + + DuplicateReports.duplicates_of(intensities, aspect, dist, dist) + |> preload([:tags, :user]) + |> Repo.all() + end + end + + defp mime(file) do + {:ok, mime} = Philomena.Mime.file(file) + + {mime, file} + end + + defp analyze({mime, file}) do + case Processors.analyzers(mime) do + nil -> :error + a -> {a.analyze(file), mime, file} + end + end + + defp intensities(:error), do: :error + defp intensities({analysis, mime, file}) do + {analysis, Processors.processors(mime).intensities(analysis, file)} + end + + # The distance metric is taxicab distance, not Euclidean, + # because this is more efficient to index. + defp normalize_dist(%{"distance" => distance}) do + distance + |> String.to_float() + |> max(0.01) + |> min(1.0) + end + defp normalize_dist(_dist), do: 0.25 +end \ No newline at end of file diff --git a/lib/philomena_web/router.ex b/lib/philomena_web/router.ex index d5f107bf..9b666e64 100644 --- a/lib/philomena_web/router.ex +++ b/lib/philomena_web/router.ex @@ -21,19 +21,19 @@ defmodule PhilomenaWeb.Router do plug PhilomenaWeb.ChannelPlug end - pipeline :rss do - plug :accepts, ["rss"] - + pipeline :api do plug PhilomenaWeb.ApiTokenPlug - plug Pow.Plug.RequireAuthenticated, - error_handler: Pow.Phoenix.PlugErrorHandler plug PhilomenaWeb.EnsureUserEnabledPlug plug PhilomenaWeb.CurrentFilterPlug plug PhilomenaWeb.ImageFilterPlug plug PhilomenaWeb.PaginationPlug end - pipeline :api do + pipeline :accepts_rss do + plug :accepts, ["rss"] + end + + pipeline :accepts_json do plug :accepts, ["json"] end @@ -66,12 +66,21 @@ defmodule PhilomenaWeb.Router do end end - scope "/api/rss", PhilomenaWeb.Api, as: :api_rss do - pipe_through :rss - + scope "/api/v1/rss", PhilomenaWeb.Api.Rss, as: :api_rss do + pipe_through [:accepts_rss, :protected, :api] resources "/watched", WatchedController, only: [:index] end + scope "/api/v1/json", PhilomenaWeb.Api.Json, as: :api_json do + pipe_through [:accepts_json, :api] + resources "/images", ImageController, only: [:show] + + scope "/search", Search, as: :search do + resources "/reverse", ReverseController, only: [:create] + end + resources "/search", SearchController, only: [:index] + end + scope "/", PhilomenaWeb do pipe_through [:browser, :ensure_totp, :protected] diff --git a/lib/philomena_web/templates/api/watched/index.rss.eex b/lib/philomena_web/templates/api/rss/watched/index.rss.eex similarity index 100% rename from lib/philomena_web/templates/api/watched/index.rss.eex rename to lib/philomena_web/templates/api/rss/watched/index.rss.eex diff --git a/lib/philomena_web/views/api/watched_view.ex b/lib/philomena_web/views/api/rss/watched_view.ex similarity index 83% rename from lib/philomena_web/views/api/watched_view.ex rename to lib/philomena_web/views/api/rss/watched_view.ex index 4444d628..0b4d7989 100644 --- a/lib/philomena_web/views/api/watched_view.ex +++ b/lib/philomena_web/views/api/rss/watched_view.ex @@ -1,4 +1,4 @@ -defmodule PhilomenaWeb.Api.WatchedView do +defmodule PhilomenaWeb.Api.Rss.WatchedView do use PhilomenaWeb, :view alias PhilomenaWeb.ImageView