galleries index

This commit is contained in:
byte[] 2019-11-17 23:47:09 -05:00
parent de48c06f99
commit 1ad4f8f076
12 changed files with 186 additions and 10 deletions

View file

@ -1,3 +1,3 @@
alias Philomena.{Repo, Comments.Comment, Posts.Post, Images.Image, Tags.Tag, Users.User} alias Philomena.{Repo, Comments.Comment, Galleries.Gallery, Posts.Post, Images.Image, Topics.Topic, Tags.Tag, Users.User}
import Ecto.Query import Ecto.Query
import Ecto.Changeset import Ecto.Changeset

View file

@ -0,0 +1,46 @@
defmodule Philomena.Galleries.Elasticsearch do
def mapping do
%{
settings: %{
index: %{
number_of_shards: 5,
max_result_window: 10_000_000
}
},
mappings: %{
gallery: %{
_all: %{enabled: false},
dynamic: false,
properties: %{
id: %{type: "integer"}, # keyword
image_count: %{type: "integer"},
watcher_count: %{type: "integer"},
updated_at: %{type: "date"},
created_at: %{type: "date"},
title: %{type: "keyword"},
creator: %{type: "keyword"}, # missing creator_id
image_ids: %{type: "keyword"},
watcher_ids: %{type: "keyword"}, # ???
description: %{type: "text", analyzer: "snowball"}
}
}
}
}
end
# [:subscribers, :creator, :interactions]
def as_json(gallery) do
%{
id: gallery.id,
image_count: gallery.image_count,
watcher_count: length(gallery.subscribers),
watcher_ids: Enum.map(gallery.subscribers, & &1.id),
updated_at: gallery.updated_at,
created_at: gallery.created_at,
title: String.downcase(gallery.title),
creator: String.downcase(gallery.creator.name),
image_ids: Enum.map(gallery.interactions, & &1.image_id),
description: gallery.description
}
end
end

View file

@ -2,6 +2,11 @@ defmodule Philomena.Galleries.Gallery do
use Ecto.Schema use Ecto.Schema
import Ecto.Changeset import Ecto.Changeset
use Philomena.Elasticsearch,
definition: Philomena.Galleries.Elasticsearch,
index_name: "galleries",
doc_type: "gallery"
alias Philomena.Images.Image alias Philomena.Images.Image
alias Philomena.Users.User alias Philomena.Users.User

View file

@ -141,7 +141,7 @@ defmodule Philomena.Images do
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
def create_subscription(image, nil), do: {:ok, nil} def create_subscription(_image, nil), do: {:ok, nil}
def create_subscription(image, user) do def create_subscription(image, user) do
%Subscription{image_id: image.id, user_id: user.id} %Subscription{image_id: image.id, user_id: user.id}
|> Subscription.changeset(%{}) |> Subscription.changeset(%{})

View file

@ -123,7 +123,7 @@ defmodule Philomena.Topics do
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
def create_subscription(topic, nil), do: {:ok, nil} def create_subscription(_topic, nil), do: {:ok, nil}
def create_subscription(topic, user) do def create_subscription(topic, user) do
%Subscription{topic_id: topic.id, user_id: user.id} %Subscription{topic_id: topic.id, user_id: user.id}
|> Subscription.changeset(%{}) |> Subscription.changeset(%{})

View file

@ -38,7 +38,7 @@ defmodule PhilomenaWeb.CommentController do
end end
defp parse_search(_conn, _params), do: [%{match_all: %{}}] defp parse_search(_conn, _params), do: [%{match_all: %{}}]
defp parse_author(%{"author" => author}) when author not in [nil, ""] do defp parse_author(%{"author" => author}) when is_binary(author) and author not in [nil, ""] do
case String.contains?(author, ["*", "?"]) do case String.contains?(author, ["*", "?"]) do
true -> true ->
[ [
@ -55,7 +55,7 @@ defmodule PhilomenaWeb.CommentController do
end end
defp parse_author(_params), do: [] defp parse_author(_params), do: []
defp parse_image_id(conn, %{"image_id" => image_id}) when image_id not in [nil, ""] do defp parse_image_id(conn, %{"image_id" => image_id}) when is_binary(image_id) and image_id not in [nil, ""] do
with {image_id, _rest} <- Integer.parse(image_id), with {image_id, _rest} <- Integer.parse(image_id),
true <- valid_image?(conn.assigns.current_user, image_id) true <- valid_image?(conn.assigns.current_user, image_id)
do do
@ -67,7 +67,7 @@ defmodule PhilomenaWeb.CommentController do
end end
defp parse_image_id(_conn, _params), do: [] defp parse_image_id(_conn, _params), do: []
defp parse_body(%{"body" => body}) when body not in [nil, ""], defp parse_body(%{"body" => body}) when is_binary(body) and body not in [nil, ""],
do: [%{match: %{body: body}}] do: [%{match: %{body: body}}]
defp parse_body(_params), do: [] defp parse_body(_params), do: []

View file

@ -0,0 +1,69 @@
defmodule PhilomenaWeb.GalleryController do
use PhilomenaWeb, :controller
alias Philomena.Galleries.Gallery
import Ecto.Query
plug :load_resource, model: Gallery, preload: [:thumbnail, :creator]
def index(conn, params) do
galleries =
Gallery.search_records(
%{
query: %{
bool: %{
must: parse_search(params)
}
},
sort: parse_sort(params),
},
conn.assigns.pagination,
Gallery |> preload([:thumbnail, :creator])
)
render(conn, "index.html", galleries: galleries, layout_class: "layout--wide")
end
def show(_conn, _params) do
end
defp parse_search(%{"gallery" => gallery_params}) do
parse_title(gallery_params) ++
parse_creator(gallery_params) ++
parse_included_image(gallery_params) ++
parse_description(gallery_params)
end
defp parse_search(_params), do: [%{match_all: %{}}]
defp parse_title(%{"title" => title}) when is_binary(title) and title not in [nil, ""],
do: [%{wildcard: %{title: "*" <> String.downcase(title) <> "*"}}]
defp parse_title(_params), do: []
defp parse_creator(%{"creator" => creator}) when is_binary(creator) and creator not in [nil, ""],
do: [%{term: %{creator: String.downcase(creator)}}]
defp parse_creator(_params), do: []
defp parse_included_image(%{"include_image" => image_id}) when is_binary(image_id) and image_id not in [nil, ""] do
with {image_id, _rest} <- Integer.parse(image_id) do
[%{term: %{image_id: image_id}}]
else
_ ->
[]
end
end
defp parse_included_image(_params), do: []
defp parse_description(%{"description" => description}) when is_binary(description) and description not in [nil, ""],
do: [%{match: %{description: %{query: description, operator: :and}}}]
defp parse_description(_params), do: []
defp parse_sort(%{"gallery" => %{"sf" => sf, "sd" => sd}})
when sf in ["created_at", "updated_at", "image_count", "_score"]
and sd in ["desc", "asc"]
do
%{sf => sd}
end
defp parse_sort(_params) do
%{created_at: :desc}
end
end

View file

@ -49,7 +49,7 @@ defmodule PhilomenaWeb.PostController do
end end
defp parse_search(_conn, _params), do: [%{match_all: %{}}] defp parse_search(_conn, _params), do: [%{match_all: %{}}]
defp parse_author(%{"author" => author}) when author not in [nil, ""] do defp parse_author(%{"author" => author}) when is_binary(author) and author not in [nil, ""] do
case String.contains?(author, ["*", "?"]) do case String.contains?(author, ["*", "?"]) do
true -> true ->
[ [
@ -66,12 +66,12 @@ defmodule PhilomenaWeb.PostController do
end end
defp parse_author(_params), do: [] defp parse_author(_params), do: []
defp parse_subject(%{"subject" => subject}) when subject not in [nil, ""] do defp parse_subject(%{"subject" => subject}) when is_binary(subject) and subject not in [nil, ""] do
[%{match: %{subject: %{query: subject, operator: "and"}}}] [%{match: %{subject: %{query: subject, operator: "and"}}}]
end end
defp parse_subject(_params), do: [] defp parse_subject(_params), do: []
defp parse_forum_id(conn, %{"forum_id" => forum_id}) when forum_id not in [nil, ""] do defp parse_forum_id(conn, %{"forum_id" => forum_id}) when is_binary(forum_id) and forum_id not in [nil, ""] do
with {forum_id, _rest} <- Integer.parse(forum_id), with {forum_id, _rest} <- Integer.parse(forum_id),
true <- valid_forum?(conn.assigns.current_user, forum_id) true <- valid_forum?(conn.assigns.current_user, forum_id)
do do
@ -83,7 +83,7 @@ defmodule PhilomenaWeb.PostController do
end end
defp parse_forum_id(_conn, _params), do: [] defp parse_forum_id(_conn, _params), do: []
defp parse_body(%{"body" => body}) when body not in [nil, ""], defp parse_body(%{"body" => body}) when is_binary(body) and body not in [nil, ""],
do: [%{match: %{body: body}}] do: [%{match: %{body: body}}]
defp parse_body(_params), do: [] defp parse_body(_params), do: []

View file

@ -100,6 +100,7 @@ defmodule PhilomenaWeb.Router do
resources "/captchas", CaptchaController, only: [:create] resources "/captchas", CaptchaController, only: [:create]
resources "/posts", PostController, only: [:index] resources "/posts", PostController, only: [:index]
resources "/commissions", CommissionController, only: [:index, :show] resources "/commissions", CommissionController, only: [:index, :show]
resources "/galleries", GalleryController, only: [:index, :show]
get "/:id", ImageController, :show get "/:id", ImageController, :show
end end

View file

@ -0,0 +1,10 @@
.media-box
a.media-box__header.media-box__header--link href=Routes.gallery_path(@conn, :show, @gallery) title=@gallery.title
= @gallery.title
.media-box__overlay
= @gallery.spoiler_warning
.media-box__content.media-box__content--large
a href=Routes.gallery_path(@conn, :show, @gallery)
= render PhilomenaWeb.ImageView, "_image_container.html", image: @gallery.thumbnail, size: :thumb, conn: @conn

View file

@ -0,0 +1,42 @@
elixir:
route = fn p -> Routes.gallery_path(@conn, :index, p) end
pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @galleries, route: route
.column-layout
.column-layout__left
.block
.block__content
h3 Search Galleries
= form_for @conn, Routes.gallery_path(@conn, :index), [as: :gallery, method: "get", class: "hform"], fn f ->
.field = label f, :title, "Title"
.field = text_input f, :title, class: "input hform__text", placeholder: "Gallery title (* as wildcard)"
.field = label f, :description, "Description"
.field = textarea f, :description, class: "input hform__text", placeholder: "Gallery description"
.field = label f, :creator, "Creator"
.field = text_input f, :creator, class: "input hform__text", placeholder: "Gallery creator (exact match)"
.field = label f, :include_image, "Include image"
.field = number_input f, :include_image, class: "input hform__text", placeholder: "Image ID (e.g. 100)"
.field = label f, :sf, "Sort by"
.field
=> select f, :sf, ["Creation Date": "created_at", "Update Date": "updated_at", "Image Count": "image_count", "Relevance": "_score"], class: "input"
=> select f, :sd, ["Descending": "desc", "Ascending": "asc"], class: "input"
.field
= submit "Search", class: "button button--state-primary"
.column-layout__main
.block
.block__header
= pagination
.block__content.js-resizable-media-container
= for gallery <- @galleries do
= render PhilomenaWeb.GalleryView, "_gallery.html", gallery: gallery, conn: @conn
.block__header.block__header--light
= pagination

View file

@ -0,0 +1,3 @@
defmodule PhilomenaWeb.GalleryView do
use PhilomenaWeb, :view
end