mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-23 20:18:00 +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),
|
||||
image_tag_ids: comment.image.tags |> Enum.map(& &1.id),
|
||||
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
|
||||
}
|
||||
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
|
||||
import Ecto.Changeset
|
||||
|
||||
use Philomena.Elasticsearch,
|
||||
definition: Philomena.Posts.Elasticsearch,
|
||||
index_name: "posts",
|
||||
doc_type: "post"
|
||||
|
||||
alias Philomena.Users.User
|
||||
alias Philomena.Topics.Topic
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
defmodule PhilomenaWeb.CommentController do
|
||||
use PhilomenaWeb, :controller
|
||||
|
||||
alias Philomena.{Comments.Comment, Textile.Renderer}
|
||||
alias Philomena.{Images.Image, Comments.Comment, Textile.Renderer}
|
||||
alias Philomena.Repo
|
||||
import Ecto.Query
|
||||
|
||||
def index(conn, params) do
|
||||
|
@ -10,7 +11,7 @@ defmodule PhilomenaWeb.CommentController do
|
|||
%{
|
||||
query: %{
|
||||
bool: %{
|
||||
must: parse_search(params) ++ [%{term: %{hidden_from_users: false}}]
|
||||
must: parse_search(conn, params) ++ [%{term: %{hidden_from_users: false}}]
|
||||
}
|
||||
},
|
||||
sort: parse_sort(params)
|
||||
|
@ -29,12 +30,12 @@ defmodule PhilomenaWeb.CommentController do
|
|||
render(conn, "index.html", comments: comments)
|
||||
end
|
||||
|
||||
defp parse_search(%{"comment" => comment_params}) do
|
||||
defp parse_search(conn, %{"comment" => comment_params}) do
|
||||
parse_author(comment_params) ++
|
||||
parse_image_id(comment_params) ++
|
||||
parse_image_id(conn, comment_params) ++
|
||||
parse_body(comment_params)
|
||||
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
|
||||
case String.contains?(author, ["*", "?"]) do
|
||||
|
@ -53,11 +54,12 @@ defmodule PhilomenaWeb.CommentController do
|
|||
end
|
||||
defp parse_author(_params), do: []
|
||||
|
||||
defp parse_image_id(%{"image_id" => image_id}) when image_id not in [nil, ""] do
|
||||
case Integer.parse(image_id) do
|
||||
{image_id, _rest} ->
|
||||
[%{term: %{image_id: image_id}}]
|
||||
|
||||
defp parse_image_id(conn, %{"image_id" => image_id}) when image_id not in [nil, ""] do
|
||||
with {image_id, _rest} <- Integer.parse(image_id),
|
||||
true <- valid_image?(conn.assigns.current_user, image_id)
|
||||
do
|
||||
[%{term: %{image_id: image_id}}]
|
||||
else
|
||||
_error ->
|
||||
[]
|
||||
end
|
||||
|
@ -74,4 +76,13 @@ defmodule PhilomenaWeb.CommentController do
|
|||
defp parse_sort(_params) do
|
||||
%{posted_at: :desc}
|
||||
end
|
||||
|
||||
defp valid_image?(user, image_id) do
|
||||
image =
|
||||
Image
|
||||
|> where(id: ^image_id)
|
||||
|> Repo.one()
|
||||
|
||||
Canada.Can.can?(user, :show, image)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,105 @@
|
|||
defmodule PhilomenaWeb.PostController do
|
||||
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
|
|
@ -96,6 +96,7 @@ defmodule PhilomenaWeb.Router do
|
|||
resources "/filters", FilterController
|
||||
resources "/profiles", ProfileController, only: [:show]
|
||||
resources "/captchas", CaptchaController, only: [:create]
|
||||
resources "/posts", PostController, only: [:index]
|
||||
|
||||
get "/:id", ImageController, :show
|
||||
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