mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-23 20:18:00 +01:00
scrivener
This commit is contained in:
parent
5d5549c457
commit
3a8176b47a
16 changed files with 195 additions and 17 deletions
|
@ -9,6 +9,7 @@ defmodule Philomena.Elasticsearch do
|
|||
quote do
|
||||
alias Philomena.Repo
|
||||
import Ecto.Query, warn: false
|
||||
require Logger
|
||||
|
||||
def create_index! do
|
||||
Elastix.Index.create(
|
||||
|
@ -81,7 +82,11 @@ defmodule Philomena.Elasticsearch do
|
|||
reindex(ecto_query, batch_size, ids)
|
||||
end
|
||||
|
||||
def search_results(elastic_query) do
|
||||
def search_results(elastic_query, pagination_params \\ %{}) do
|
||||
page_number = pagination_params[:page_number] || 1
|
||||
page_size = pagination_params[:page_size] || 25
|
||||
elastic_query = Map.merge(elastic_query, %{from: (page_number - 1) * page_size, size: page_size, _source: false})
|
||||
|
||||
{:ok, %{body: results, status_code: 200}} =
|
||||
Elastix.Search.search(
|
||||
unquote(elastic_url),
|
||||
|
@ -90,16 +95,32 @@ defmodule Philomena.Elasticsearch do
|
|||
elastic_query
|
||||
)
|
||||
|
||||
results
|
||||
time = results["took"]
|
||||
count = results["hits"]["total"]
|
||||
entries = results["hits"]["hits"] |> Enum.map(&String.to_integer(&1["_id"]))
|
||||
|
||||
Logger.debug("[Elasticsearch] Query took #{time}ms")
|
||||
|
||||
%Scrivener.Page{
|
||||
entries: entries,
|
||||
page_number: page_number,
|
||||
page_size: page_size,
|
||||
total_entries: count,
|
||||
total_pages: div(count + page_size - 1, page_size)
|
||||
}
|
||||
end
|
||||
|
||||
def search_records(elastic_query, ecto_query \\ __MODULE__) do
|
||||
results = search_results(elastic_query)
|
||||
def search_records(elastic_query, pagination_params \\ %{}, ecto_query \\ __MODULE__) do
|
||||
page = search_results(elastic_query, pagination_params)
|
||||
ids = page.entries
|
||||
|
||||
ids = results["hits"]["hits"] |> Enum.map(&String.to_integer(&1["_id"]))
|
||||
records = ecto_query |> where([m], m.id in ^ids) |> Repo.all()
|
||||
records =
|
||||
ecto_query
|
||||
|> where([m], m.id in ^ids)
|
||||
|> Repo.all()
|
||||
|> Enum.sort_by(&Enum.find_index(ids, fn el -> el == &1.id end))
|
||||
|
||||
records |> Enum.sort_by(&Enum.find_index(ids, fn el -> el == &1.id end))
|
||||
%{page | entries: records}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,4 +2,6 @@ defmodule Philomena.Repo do
|
|||
use Ecto.Repo,
|
||||
otp_app: :philomena,
|
||||
adapter: Ecto.Adapters.Postgres
|
||||
|
||||
use Scrivener, page_size: 250
|
||||
end
|
||||
|
|
|
@ -19,9 +19,9 @@ defmodule PhilomenaWeb.ActivityController do
|
|||
must: image_query
|
||||
}
|
||||
},
|
||||
size: 25,
|
||||
sort: %{created_at: :desc}
|
||||
},
|
||||
%{page_number: 1, page_size: 25},
|
||||
Image |> preload([:tags])
|
||||
)
|
||||
|
||||
|
@ -34,10 +34,9 @@ defmodule PhilomenaWeb.ActivityController do
|
|||
must: %{range: %{first_seen_at: %{gt: "now-3d"}}}
|
||||
}
|
||||
},
|
||||
size: 4,
|
||||
from: :rand.uniform(26) - 1,
|
||||
sort: [%{score: :desc}, %{first_seen_at: :desc}]
|
||||
},
|
||||
%{page_number: :rand.uniform(6), page_size: 4},
|
||||
Image |> preload([:tags])
|
||||
)
|
||||
|
||||
|
@ -55,9 +54,9 @@ defmodule PhilomenaWeb.ActivityController do
|
|||
]
|
||||
}
|
||||
},
|
||||
size: 6,
|
||||
sort: %{posted_at: :desc}
|
||||
},
|
||||
%{page_number: 1, page_size: 6},
|
||||
Comment |> preload([:user, :image])
|
||||
)
|
||||
|
||||
|
@ -72,9 +71,9 @@ defmodule PhilomenaWeb.ActivityController do
|
|||
must: watched_query
|
||||
}
|
||||
},
|
||||
size: 25,
|
||||
sort: %{created_at: :desc}
|
||||
},
|
||||
%{page_number: 1, page_size: 25},
|
||||
Image |> preload([:tags])
|
||||
)
|
||||
end
|
||||
|
|
|
@ -16,6 +16,7 @@ defmodule PhilomenaWeb.ImageController do
|
|||
query: %{bool: %{must_not: [query, %{term: %{hidden_from_users: true}}]}},
|
||||
sort: %{created_at: :desc}
|
||||
},
|
||||
conn.assigns.pagination,
|
||||
Image |> preload([:tags, :user])
|
||||
)
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ defmodule PhilomenaWeb.SearchController do
|
|||
query: %{bool: %{must: query, must_not: [filter, %{term: %{hidden_from_users: true}}]}},
|
||||
sort: %{created_at: :desc}
|
||||
},
|
||||
conn.assigns.pagination,
|
||||
Image |> preload(:tags)
|
||||
)
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ defmodule PhilomenaWeb.TagController do
|
|||
size: 250,
|
||||
sort: [%{images: :desc}, %{name: :asc}]
|
||||
},
|
||||
%{conn.assigns.pagination | page_size: 250},
|
||||
Tag
|
||||
)
|
||||
|
||||
|
@ -36,6 +37,7 @@ defmodule PhilomenaWeb.TagController do
|
|||
},
|
||||
sort: %{created_at: :desc}
|
||||
},
|
||||
conn.assigns.pagination,
|
||||
Image |> preload([:tags, :user])
|
||||
)
|
||||
|
||||
|
|
35
lib/philomena_web/plugs/pagination.ex
Normal file
35
lib/philomena_web/plugs/pagination.ex
Normal file
|
@ -0,0 +1,35 @@
|
|||
defmodule PhilomenaWeb.Plugs.Pagination do
|
||||
import Plug.Conn
|
||||
|
||||
# No options
|
||||
def init([]), do: false
|
||||
|
||||
# Assign pagination info
|
||||
def call(conn, _opts) do
|
||||
conn = conn |> fetch_query_params()
|
||||
params = conn.params
|
||||
|
||||
page_number =
|
||||
case Integer.parse(params["page"] |> to_string()) do
|
||||
{int, _rest} ->
|
||||
int
|
||||
_ ->
|
||||
1
|
||||
end
|
||||
|
||||
page_number = page_number |> max(1)
|
||||
|
||||
page_size =
|
||||
case Integer.parse(params["per_page"] |> to_string()) do
|
||||
{int, _rest} ->
|
||||
int
|
||||
_ ->
|
||||
25
|
||||
end
|
||||
|
||||
page_size = page_size |> max(1) |> min(50)
|
||||
|
||||
conn
|
||||
|> assign(:pagination, %{page_number: page_number, page_size: page_size})
|
||||
end
|
||||
end
|
|
@ -9,6 +9,7 @@ defmodule PhilomenaWeb.Router do
|
|||
plug :protect_from_forgery
|
||||
plug :put_secure_browser_headers
|
||||
plug PhilomenaWeb.Plugs.ImageFilter
|
||||
plug PhilomenaWeb.Plugs.Pagination
|
||||
end
|
||||
|
||||
pipeline :api do
|
||||
|
@ -26,6 +27,7 @@ defmodule PhilomenaWeb.Router do
|
|||
|
||||
get "/", ActivityController, :index
|
||||
|
||||
resources "/activity", ActivityController, only: [:index]
|
||||
resources "/images", ImageController, only: [:index, :show]
|
||||
resources "/tags", TagController, only: [:index, :show]
|
||||
resources "/search", SearchController, only: [:index]
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
' Most Commented-on Images
|
||||
|
||||
.column-layout__main
|
||||
= render PhilomenaWeb.ImageView, "index.html", images: @images, size: :thumb
|
||||
= render PhilomenaWeb.ImageView, "index.html", conn: @conn, images: @images, size: :thumb
|
||||
= if !!@watched and @watched != [] do
|
||||
.block
|
||||
.block__header
|
||||
|
@ -49,4 +49,4 @@
|
|||
span.hide-mobile
|
||||
' Browse Watched Images
|
||||
.block__content.js-resizable-media-container
|
||||
= render PhilomenaWeb.ImageView, "index.html", images: @watched, size: :thumb_small
|
||||
= render PhilomenaWeb.ImageView, "index.html", conn: @conn, images: @watched, size: :thumb_small
|
||||
|
|
|
@ -1,4 +1,25 @@
|
|||
- header = assigns[:header] || ""
|
||||
- route = assigns[:route] || fn p -> Routes.image_path(@conn, :index, p) end
|
||||
- pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @images, route: route
|
||||
- info = render PhilomenaWeb.PaginationView, "_pagination_info.html", page: @images
|
||||
|
||||
.block#imagelist-container
|
||||
section.block__header.flex
|
||||
h1.block__header__title.hide-mobile
|
||||
=> header
|
||||
= pagination
|
||||
|
||||
.block__content.js-resizable-media-container
|
||||
= for image <- @images do
|
||||
= render PhilomenaWeb.ImageView, "_image_box.html", image: image, size: assigns[:size] || :thumb
|
||||
= render PhilomenaWeb.ImageView, "_image_box.html", image: image, size: assigns[:size] || :thumb
|
||||
|
||||
.block__header.block__header--light.flex
|
||||
= pagination
|
||||
|
||||
span.block__header__title
|
||||
= info
|
||||
.flex__right
|
||||
a href="/settings/edit" title="Display Settings"
|
||||
i.fa.fa-cog
|
||||
span.hide-mobile.hide-limited-desktop<>
|
||||
' Display Settings
|
|
@ -0,0 +1,27 @@
|
|||
- params = assigns[:params] || []
|
||||
|
||||
= if @page.total_pages > 1 do
|
||||
nav.pagination
|
||||
= if not first_page?(@page) do
|
||||
= link("« First", to: first_page_path(@page, @route, params))
|
||||
= link("‹ Prev", to: prev_page_path(@page, @route, params))
|
||||
|
||||
= if left_gap?(@page) do
|
||||
span.page.gap
|
||||
' …
|
||||
|
||||
= for number <- left_page_numbers(@page) do
|
||||
= link(number, to: page_path(@route, params, number))
|
||||
|
||||
span.page-current = @page.page_number
|
||||
|
||||
= for number <- right_page_numbers(@page) do
|
||||
= link(number, to: page_path(@route, params, number))
|
||||
|
||||
= if right_gap?(@page) do
|
||||
span.page.gap
|
||||
' …
|
||||
|
||||
= if not last_page?(@page) do
|
||||
= link("Next ›", to: next_page_path(@page, @route, params))
|
||||
= link("Last »", to: last_page_path(@page, @route, params))
|
|
@ -0,0 +1,13 @@
|
|||
' Showing
|
||||
= if @page.total_entries == 1 do
|
||||
' result
|
||||
- else
|
||||
' results
|
||||
strong
|
||||
=> max(((@page.page_number - 1) * @page.page_size) - 1, 1)
|
||||
' -
|
||||
=> min(@page.page_number * @page.page_size, @page.total_entries)
|
||||
' of
|
||||
strong
|
||||
=> @page.total_entries
|
||||
' total
|
|
@ -1 +1,6 @@
|
|||
= render PhilomenaWeb.TagView, "_tag_list.html", tags: @tags
|
||||
= render PhilomenaWeb.TagView, "_tag_list.html", tags: @tags
|
||||
.block
|
||||
.block__header.block__header--light.flex
|
||||
= render PhilomenaWeb.PaginationView, "_pagination.html", page: @tags, route: fn p -> Routes.tag_path(@conn, :index, p) end
|
||||
span.block__header__title
|
||||
= render PhilomenaWeb.PaginationView, "_pagination_info.html", page: @tags
|
46
lib/philomena_web/views/pagination_view.ex
Normal file
46
lib/philomena_web/views/pagination_view.ex
Normal file
|
@ -0,0 +1,46 @@
|
|||
defmodule PhilomenaWeb.PaginationView do
|
||||
use PhilomenaWeb, :view
|
||||
|
||||
def first_page?(page) do
|
||||
page.page_number == 1
|
||||
end
|
||||
|
||||
def last_page?(page) do
|
||||
page.page_number == page.total_pages
|
||||
end
|
||||
|
||||
def page_path(route, params, number) do
|
||||
route.(Keyword.merge(params, page: number))
|
||||
end
|
||||
|
||||
def first_page_path(_page, route, params), do: page_path(route, params, 1)
|
||||
def prev_page_path(page, route, params), do: page_path(route, params, page.page_number - 1)
|
||||
def next_page_path(page, route, params), do: page_path(route, params, page.page_number + 1)
|
||||
def last_page_path(page, route, params), do: page_path(route, params, page.total_pages)
|
||||
|
||||
def left_gap?(page) do
|
||||
page.page_number >= 5
|
||||
end
|
||||
|
||||
def left_page_numbers(page) do
|
||||
number = page.page_number
|
||||
min = 1
|
||||
max = page.total_pages
|
||||
|
||||
(number - 5..number)
|
||||
|> Enum.filter(& &1 >= min and &1 != number and &1 <= max)
|
||||
end
|
||||
|
||||
def right_gap?(page) do
|
||||
page.total_pages - page.page_number >= 5
|
||||
end
|
||||
|
||||
def right_page_numbers(page) do
|
||||
number = page.page_number
|
||||
min = 1
|
||||
max = page.total_pages
|
||||
|
||||
(number .. number + 5)
|
||||
|> Enum.filter(& &1 >= min and &1 != number and &1 <= max)
|
||||
end
|
||||
end
|
3
mix.exs
3
mix.exs
|
@ -51,7 +51,8 @@ defmodule Philomena.MixProject do
|
|||
{:secure_compare, "~> 0.1.0"},
|
||||
{:elastix, "~> 0.7.1"},
|
||||
{:nimble_parsec, "~> 0.5.1"},
|
||||
{:canary, "~> 1.1.1"}
|
||||
{:canary, "~> 1.1.1"},
|
||||
{:scrivener_ecto, "~> 2.0"}
|
||||
]
|
||||
end
|
||||
|
||||
|
|
2
mix.lock
2
mix.lock
|
@ -40,6 +40,8 @@
|
|||
"pow": {:hex, :pow, "1.0.13", "5ca3e8d9fecca037bfb0ea3b8dde070cc319746498e844d59fc209d461b0d426", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.3.0 or ~> 1.4.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 2.0.0 and <= 3.0.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:plug, ">= 1.5.0 and < 2.0.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm"},
|
||||
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"},
|
||||
"retry": {:hex, :retry, "0.13.0", "bb9b2713f70f39337837852337ad280c77662574f4fb852a8386c269f3d734c4", [:mix], [], "hexpm"},
|
||||
"scrivener": {:hex, :scrivener, "2.7.0", "fa94cdea21fad0649921d8066b1833d18d296217bfdf4a5389a2f45ee857b773", [:mix], [], "hexpm"},
|
||||
"scrivener_ecto": {:hex, :scrivener_ecto, "2.2.0", "53d5f1ba28f35f17891cf526ee102f8f225b7024d1cdaf8984875467158c9c5e", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:scrivener, "~> 2.4", [hex: :scrivener, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"secure_compare": {:hex, :secure_compare, "0.1.0", "01b3c93c8edb696e8a5b38397ed48e10958c8a5ec740606656445bcbec0aadb8", [:mix], [], "hexpm"},
|
||||
"slime": {:hex, :slime, "1.2.0", "d46ede53c96b743dfdd23821268dc9b01f04ffea65d9d57c4e3d9200b162df02", [:mix], [{:neotoma, "~> 1.7", [hex: :neotoma, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm"},
|
||||
|
|
Loading…
Reference in a new issue