mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-27 21:47:59 +01:00
add post search
This commit is contained in:
parent
d9bb4d700f
commit
5982fe4774
7 changed files with 239 additions and 13 deletions
|
@ -40,7 +40,7 @@ defmodule Philomena.Comments.Elasticsearch do
|
||||||
author: if(!!comment.user and !comment.anonymous, do: comment.user.name),
|
author: if(!!comment.user and !comment.anonymous, do: comment.user.name),
|
||||||
image_tag_ids: comment.image.tags |> Enum.map(& &1.id),
|
image_tag_ids: comment.image.tags |> Enum.map(& &1.id),
|
||||||
anonymous: comment.anonymous,
|
anonymous: comment.anonymous,
|
||||||
hidden_from_users: comment.hidden_from_users,
|
hidden_from_users: comment.image.hidden_from_users || comment.hidden_from_users,
|
||||||
body: comment.body
|
body: comment.body
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
62
lib/philomena/posts/elasticsearch.ex
Normal file
62
lib/philomena/posts/elasticsearch.ex
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
defmodule Philomena.Posts.Elasticsearch do
|
||||||
|
def mapping do
|
||||||
|
%{
|
||||||
|
settings: %{
|
||||||
|
index: %{
|
||||||
|
number_of_shards: 5,
|
||||||
|
max_result_window: 10_000_000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mappings: %{
|
||||||
|
post: %{
|
||||||
|
_all: %{enabled: false},
|
||||||
|
dynamic: false,
|
||||||
|
properties: %{
|
||||||
|
id: %{type: "integer"},
|
||||||
|
body: %{type: "text", analyzer: "snowball"},
|
||||||
|
ip: %{type: "ip"},
|
||||||
|
user_agent: %{type: "keyword"},
|
||||||
|
referrer: %{type: "keyword"},
|
||||||
|
fingerprint: %{type: "keyword"},
|
||||||
|
subject: %{type: "text", analyzer: "snowball"},
|
||||||
|
author: %{type: "keyword"},
|
||||||
|
topic_position: %{type: "integer"},
|
||||||
|
forum_id: %{type: "keyword"},
|
||||||
|
topic_id: %{type: "keyword"},
|
||||||
|
user_id: %{type: "keyword"},
|
||||||
|
anonymous: %{type: "boolean"},
|
||||||
|
updated_at: %{type: "date"},
|
||||||
|
created_at: %{type: "date"},
|
||||||
|
deleted: %{type: "boolean"},
|
||||||
|
access_level: %{type: "keyword"},
|
||||||
|
destroyed_content: %{type: "boolean"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
# [:user, topic: :forum]
|
||||||
|
def as_json(post) do
|
||||||
|
%{
|
||||||
|
id: post.id,
|
||||||
|
topic_id: post.topic_id,
|
||||||
|
body: post.body,
|
||||||
|
author: if(!!post.user and !post.anonymous, do: String.downcase(post.user.name)),
|
||||||
|
subject: post.topic.title,
|
||||||
|
ip: post.ip |> to_string(),
|
||||||
|
user_agent: post.user_agent,
|
||||||
|
referrer: post.referrer,
|
||||||
|
fingerprint: post.fingerprint,
|
||||||
|
topic_position: post.topic_position,
|
||||||
|
forum_id: post.topic.forum_id,
|
||||||
|
user_id: post.user_id,
|
||||||
|
anonymous: post.anonymous,
|
||||||
|
created_at: post.created_at,
|
||||||
|
updated_at: post.updated_at,
|
||||||
|
deleted: post.hidden_from_users,
|
||||||
|
access_level: post.topic.forum.access_level,
|
||||||
|
destroyed_content: post.destroyed_content
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,6 +2,11 @@ defmodule Philomena.Posts.Post do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
use Philomena.Elasticsearch,
|
||||||
|
definition: Philomena.Posts.Elasticsearch,
|
||||||
|
index_name: "posts",
|
||||||
|
doc_type: "post"
|
||||||
|
|
||||||
alias Philomena.Users.User
|
alias Philomena.Users.User
|
||||||
alias Philomena.Topics.Topic
|
alias Philomena.Topics.Topic
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
defmodule PhilomenaWeb.CommentController do
|
defmodule PhilomenaWeb.CommentController do
|
||||||
use PhilomenaWeb, :controller
|
use PhilomenaWeb, :controller
|
||||||
|
|
||||||
alias Philomena.{Comments.Comment, Textile.Renderer}
|
alias Philomena.{Images.Image, Comments.Comment, Textile.Renderer}
|
||||||
|
alias Philomena.Repo
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
def index(conn, params) do
|
def index(conn, params) do
|
||||||
|
@ -10,7 +11,7 @@ defmodule PhilomenaWeb.CommentController do
|
||||||
%{
|
%{
|
||||||
query: %{
|
query: %{
|
||||||
bool: %{
|
bool: %{
|
||||||
must: parse_search(params) ++ [%{term: %{hidden_from_users: false}}]
|
must: parse_search(conn, params) ++ [%{term: %{hidden_from_users: false}}]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sort: parse_sort(params)
|
sort: parse_sort(params)
|
||||||
|
@ -29,12 +30,12 @@ defmodule PhilomenaWeb.CommentController do
|
||||||
render(conn, "index.html", comments: comments)
|
render(conn, "index.html", comments: comments)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp parse_search(%{"comment" => comment_params}) do
|
defp parse_search(conn, %{"comment" => comment_params}) do
|
||||||
parse_author(comment_params) ++
|
parse_author(comment_params) ++
|
||||||
parse_image_id(comment_params) ++
|
parse_image_id(conn, comment_params) ++
|
||||||
parse_body(comment_params)
|
parse_body(comment_params)
|
||||||
end
|
end
|
||||||
defp parse_search(_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 author not in [nil, ""] do
|
||||||
case String.contains?(author, ["*", "?"]) do
|
case String.contains?(author, ["*", "?"]) do
|
||||||
|
@ -53,11 +54,12 @@ defmodule PhilomenaWeb.CommentController do
|
||||||
end
|
end
|
||||||
defp parse_author(_params), do: []
|
defp parse_author(_params), do: []
|
||||||
|
|
||||||
defp parse_image_id(%{"image_id" => image_id}) when image_id not in [nil, ""] do
|
defp parse_image_id(conn, %{"image_id" => image_id}) when image_id not in [nil, ""] do
|
||||||
case Integer.parse(image_id) do
|
with {image_id, _rest} <- Integer.parse(image_id),
|
||||||
{image_id, _rest} ->
|
true <- valid_image?(conn.assigns.current_user, image_id)
|
||||||
|
do
|
||||||
[%{term: %{image_id: image_id}}]
|
[%{term: %{image_id: image_id}}]
|
||||||
|
else
|
||||||
_error ->
|
_error ->
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
|
@ -74,4 +76,13 @@ defmodule PhilomenaWeb.CommentController do
|
||||||
defp parse_sort(_params) do
|
defp parse_sort(_params) do
|
||||||
%{posted_at: :desc}
|
%{posted_at: :desc}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp valid_image?(user, image_id) do
|
||||||
|
image =
|
||||||
|
Image
|
||||||
|
|> where(id: ^image_id)
|
||||||
|
|> Repo.one()
|
||||||
|
|
||||||
|
Canada.Can.can?(user, :show, image)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,105 @@
|
||||||
defmodule PhilomenaWeb.PostController do
|
defmodule PhilomenaWeb.PostController do
|
||||||
use PhilomenaWeb, :controller
|
use PhilomenaWeb, :controller
|
||||||
|
|
||||||
def index(conn, _params) do
|
alias Philomena.{Forums.Forum, Posts.Post, Textile.Renderer}
|
||||||
|
alias Philomena.Repo
|
||||||
|
import Ecto.Query
|
||||||
|
|
||||||
|
def index(conn, params) do
|
||||||
|
user = conn.assigns.current_user
|
||||||
|
|
||||||
|
posts =
|
||||||
|
Post.search_records(
|
||||||
|
%{
|
||||||
|
query: %{
|
||||||
|
bool: %{
|
||||||
|
must: parse_search(conn, params) ++ [%{term: %{deleted: false}}]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sort: parse_sort(params)
|
||||||
|
},
|
||||||
|
conn.assigns.pagination,
|
||||||
|
Post |> preload([topic: :forum, user: [awards: :badge]])
|
||||||
|
)
|
||||||
|
|
||||||
|
rendered =
|
||||||
|
posts.entries
|
||||||
|
|> Renderer.render_collection()
|
||||||
|
|
||||||
|
posts =
|
||||||
|
%{posts | entries: Enum.zip(posts.entries, rendered)}
|
||||||
|
|
||||||
|
forums =
|
||||||
|
Forum
|
||||||
|
|> order_by(asc: :name)
|
||||||
|
|> Repo.all()
|
||||||
|
|> Enum.filter(&Canada.Can.can?(user, :show, &1))
|
||||||
|
|> Enum.map(&{&1.name, &1.id})
|
||||||
|
|
||||||
|
forums = [{"-", ""} | forums]
|
||||||
|
|
||||||
|
render(conn, "index.html", posts: posts, forums: forums)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp parse_search(conn, %{"post" => post_params}) do
|
||||||
|
parse_author(post_params) ++
|
||||||
|
parse_subject(post_params) ++
|
||||||
|
parse_forum_id(conn, post_params) ++
|
||||||
|
parse_body(post_params)
|
||||||
|
end
|
||||||
|
defp parse_search(_conn, _params), do: [%{match_all: %{}}]
|
||||||
|
|
||||||
|
defp parse_author(%{"author" => author}) when author not in [nil, ""] do
|
||||||
|
case String.contains?(author, ["*", "?"]) do
|
||||||
|
true ->
|
||||||
|
[
|
||||||
|
%{wildcard: %{author: String.downcase(author)}},
|
||||||
|
%{term: %{anonymous: false}}
|
||||||
|
]
|
||||||
|
|
||||||
|
false ->
|
||||||
|
[
|
||||||
|
%{term: %{author: String.downcase(author)}},
|
||||||
|
%{term: %{anonymous: false}}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
defp parse_author(_params), do: []
|
||||||
|
|
||||||
|
defp parse_subject(%{"subject" => subject}) when subject not in [nil, ""] do
|
||||||
|
[%{match: %{subject: %{query: subject, operator: "and"}}}]
|
||||||
|
end
|
||||||
|
defp parse_subject(_params), do: []
|
||||||
|
|
||||||
|
defp parse_forum_id(conn, %{"forum_id" => forum_id}) when forum_id not in [nil, ""] do
|
||||||
|
with {forum_id, _rest} <- Integer.parse(forum_id),
|
||||||
|
true <- valid_forum?(conn.assigns.current_user, forum_id)
|
||||||
|
do
|
||||||
|
[%{term: %{forum_id: forum_id}}]
|
||||||
|
else
|
||||||
|
_error ->
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
defp parse_forum_id(_conn, _params), do: []
|
||||||
|
|
||||||
|
defp parse_body(%{"body" => body}) when body not in [nil, ""],
|
||||||
|
do: [%{match: %{body: body}}]
|
||||||
|
defp parse_body(_params), do: []
|
||||||
|
|
||||||
|
defp parse_sort(%{"post" => %{"sf" => sf, "sd" => sd}}) when sf in ["created_at", "_score"] and sd in ["desc", "asc"] do
|
||||||
|
%{sf => sd}
|
||||||
|
end
|
||||||
|
defp parse_sort(_params) do
|
||||||
|
%{created_at: :desc}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp valid_forum?(user, forum_id) do
|
||||||
|
forum =
|
||||||
|
Forum
|
||||||
|
|> where(id: ^forum_id)
|
||||||
|
|> Repo.one()
|
||||||
|
|
||||||
|
Canada.Can.can?(user, :show, forum)
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -96,6 +96,7 @@ defmodule PhilomenaWeb.Router do
|
||||||
resources "/filters", FilterController
|
resources "/filters", FilterController
|
||||||
resources "/profiles", ProfileController, only: [:show]
|
resources "/profiles", ProfileController, only: [:show]
|
||||||
resources "/captchas", CaptchaController, only: [:create]
|
resources "/captchas", CaptchaController, only: [:create]
|
||||||
|
resources "/posts", PostController, only: [:index]
|
||||||
|
|
||||||
get "/:id", ImageController, :show
|
get "/:id", ImageController, :show
|
||||||
end
|
end
|
||||||
|
|
49
lib/philomena_web/templates/post/index.html.slime
Normal file
49
lib/philomena_web/templates/post/index.html.slime
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
elixir:
|
||||||
|
route = fn p -> Routes.post_path(@conn, :index, p) end
|
||||||
|
pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @posts, route: route
|
||||||
|
|
||||||
|
.column-layout
|
||||||
|
.column-layout__left
|
||||||
|
.block
|
||||||
|
.block__content
|
||||||
|
h3 Search Posts
|
||||||
|
|
||||||
|
= form_for @conn, Routes.post_path(@conn, :index), [as: :post, method: "get", class: "hform"], fn f ->
|
||||||
|
.field = label f, :author, "Author"
|
||||||
|
.field = text_input f, :author, class: "input hform__text", placeholder: "Author (* is wildcard)"
|
||||||
|
|
||||||
|
.field = label f, :forum_id, "Forum"
|
||||||
|
.field = select f, :forum_id, @forums, class: "input input--wide"
|
||||||
|
|
||||||
|
.field = label f, :body, "Body"
|
||||||
|
.field = textarea f, :body, class: "input input--wide", placeholder: "Body"
|
||||||
|
|
||||||
|
.field = label f, :sf, "Sort by"
|
||||||
|
.field
|
||||||
|
=> select f, :sf, ["Creation Date": "created_at", "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
|
||||||
|
|
||||||
|
.post-search-results
|
||||||
|
= for {post, body} <- @posts do
|
||||||
|
.post-entry-wrapper
|
||||||
|
h3
|
||||||
|
=> link post.topic.forum.name, to: Routes.forum_path(@conn, :show, post.topic.forum)
|
||||||
|
' »
|
||||||
|
=> link post.topic.title, to: Routes.forum_topic_path(@conn, :show, post.topic.forum, post.topic)
|
||||||
|
' »
|
||||||
|
a href=(Routes.forum_topic_path(@conn, :show, post.topic.forum, post.topic, post_id: post.id) <> "#post_#{post.id}")
|
||||||
|
= if post.topic_position == 0 do
|
||||||
|
' Topic Opener
|
||||||
|
- else
|
||||||
|
' Post
|
||||||
|
= post.topic_position + 1
|
||||||
|
|
||||||
|
= render PhilomenaWeb.PostView, "_post.html", post: post, body: body, conn: @conn
|
Loading…
Reference in a new issue