API cursor navigation

This commit is contained in:
Liam 2024-12-01 13:09:28 -05:00
parent b45130f073
commit 1e3b3430fc
23 changed files with 292 additions and 85 deletions

View file

@ -0,0 +1,146 @@
defmodule PhilomenaQuery.Cursor do
alias PhilomenaQuery.Search
alias Philomena.Repo
import Ecto.Query
@typedoc """
The underlying cursor type, which contains the ordered sort field values
of a document.
"""
@type cursor :: [integer() | binary() | boolean()]
@typedoc """
A mapping of document IDs to cursors.
"""
@type cursor_map :: %{integer() => cursor()}
@doc """
Execute search with optional input cursor, and return results as tuple of
`{results, cursors}`.
## Example
iex> search_records(
...> %{query: ..., sort: [%{created_at: :desc}, %{id: :desc}]}
...> Image
...> )
{%Scrivener.Page{entries: [%Image{id: 1}, ...]},
%{1 => [1325394000000, 1], ...}}
"""
@spec search_records(Search.search_definition(), Search.queryable(), search_after :: term()) ::
{Scrivener.Page.t(), cursor_map()}
def search_records(search_definition, queryable, search_after) do
search_definition = search_after_definition(search_definition, search_after)
page = Search.search_records_with_hits(search_definition, queryable)
{records, cursors} =
Enum.map_reduce(page, %{}, fn {record, hit}, cursors ->
sort = Map.fetch!(hit, "sort")
{record, Map.put(cursors, record.id, sort)}
end)
{Map.put(page, :entries, records), cursors}
end
@doc """
Return page of records and cursors map based on sort.
## Example
iex> paginate(Forum, [page_size: 25], ["dis", 3], asc: :name, asc: :id)
%{4 => ["Generals", 4]}
"""
@spec paginate(
Ecto.Query.t(),
scrivener_opts :: any(),
search_after :: term(),
sorts :: Keyword.t()
) :: {Scrivener.Page.t(), cursor_map()}
def paginate(query, pagination, search_after, sorts) do
total_entries = Repo.aggregate(query, :count)
pagination = Keyword.merge(pagination, options: [total_entries: total_entries])
records =
query
|> order_by(^sorts)
|> search_after_query(search_after, sorts)
|> Repo.paginate(pagination)
fields = Keyword.values(sorts)
cursors =
Enum.reduce(records, %{}, fn record, cursors ->
field_values = Enum.map(fields, &Map.fetch!(record, &1))
Map.put(cursors, record.id, field_values)
end)
{records, cursors}
end
@spec search_after_definition(Search.search_definition(), term()) :: Search.search_definition()
defp search_after_definition(search_definition, search_after) do
search_after
|> permit_search_after()
|> case do
[] ->
search_definition
search_after ->
update_in(search_definition.body, &Map.put(&1, :search_after, search_after))
end
end
@spec search_after_query(Ecto.Query.t(), term(), Keyword.t()) :: Ecto.Query.t()
defp search_after_query(query, search_after, sorts) do
search_after = permit_search_after(search_after)
combined = Enum.zip(sorts, search_after)
case combined do
[_some | _rest] = values ->
or_clauses = dynamic([], false)
{or_clauses, _} =
Enum.reduce(values, {or_clauses, []}, fn {{sd, col}, value}, {next, equal_parts} ->
# more specific column has next value
and_clauses =
if sd == :asc do
dynamic([s], field(s, ^col) > ^value)
else
dynamic([s], field(s, ^col) < ^value)
end
# and
and_clauses =
Enum.reduce(equal_parts, and_clauses, fn {col, value}, rest ->
# less specific columns are equal
dynamic([s], field(s, ^col) == ^value and ^rest)
end)
{dynamic(^next or ^and_clauses), equal_parts ++ [{col, value}]}
end)
where(query, ^or_clauses)
_ ->
query
end
end
# Validate that search_after values are only strings, numbers, and bools
defp permit_search_after(search_after) do
search_after
|> permit_list()
|> Enum.flat_map(&permit_value/1)
end
defp permit_list(value) when is_list(value), do: value
defp permit_list(_value), do: []
defp permit_value(value) when is_binary(value) or is_number(value) or is_boolean(value),
do: [value]
defp permit_value(_value), do: []
end

View file

@ -2,18 +2,21 @@ defmodule PhilomenaWeb.Api.Json.Filter.SystemFilterController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias Philomena.Filters.Filter alias Philomena.Filters.Filter
alias Philomena.Repo alias PhilomenaQuery.Cursor
import Ecto.Query import Ecto.Query
def index(conn, _params) do def index(conn, params) do
system_filters = {system_filters, cursors} =
Filter Filter
|> where(system: true) |> where(system: true)
|> order_by(asc: :id) |> Cursor.paginate(conn.assigns.scrivener, params["search_after"], asc: :id)
|> Repo.paginate(conn.assigns.scrivener)
conn conn
|> put_view(PhilomenaWeb.Api.Json.FilterView) |> put_view(PhilomenaWeb.Api.Json.FilterView)
|> render("index.json", filters: system_filters, total: system_filters.total_entries) |> render("index.json",
cursors: cursors,
filters: system_filters,
total: system_filters.total_entries
)
end end
end end

View file

@ -2,10 +2,10 @@ defmodule PhilomenaWeb.Api.Json.Filter.UserFilterController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias Philomena.Filters.Filter alias Philomena.Filters.Filter
alias Philomena.Repo alias PhilomenaQuery.Cursor
import Ecto.Query import Ecto.Query
def index(conn, _params) do def index(conn, params) do
user = conn.assigns.current_user user = conn.assigns.current_user
case user do case user do
@ -15,15 +15,18 @@ defmodule PhilomenaWeb.Api.Json.Filter.UserFilterController do
|> text("") |> text("")
_ -> _ ->
user_filters = {user_filters, cursors} =
Filter Filter
|> where(user_id: ^user.id) |> where(user_id: ^user.id)
|> order_by(asc: :id) |> Cursor.paginate(conn.assigns.scrivener, params["search_after"], asc: :id)
|> Repo.paginate(conn.assigns.scrivener)
conn conn
|> put_view(PhilomenaWeb.Api.Json.FilterView) |> put_view(PhilomenaWeb.Api.Json.FilterView)
|> render("index.json", filters: user_filters, total: user_filters.total_entries) |> render("index.json",
cursors: cursors,
filters: user_filters,
total: user_filters.total_entries
)
end end
end end
end end

View file

@ -1,39 +1,46 @@
defmodule PhilomenaWeb.Api.Json.Forum.Topic.PostController do defmodule PhilomenaWeb.Api.Json.Forum.Topic.PostController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias Philomena.Topics.Topic
alias Philomena.Posts.Post alias Philomena.Posts.Post
alias PhilomenaQuery.Cursor
alias Philomena.Repo alias Philomena.Repo
import Ecto.Query import Ecto.Query
def index(conn, %{
"forum_id" => forum_id,
"topic_id" => topic_id,
"search_after" => search_after
}) do
topic = Repo.one!(topic_query(topic_id, forum_id))
{posts, cursors} =
post_query(topic_id, forum_id)
|> Cursor.paginate(conn.assigns.scrivener, search_after, asc: :topic_position)
render(conn, "index.json", cursors: cursors, posts: posts, total: topic.post_count)
end
def index(conn, %{"forum_id" => forum_id, "topic_id" => topic_id}) do def index(conn, %{"forum_id" => forum_id, "topic_id" => topic_id}) do
page = conn.assigns.pagination.page_number page = conn.assigns.pagination.page_number
posts = topic = Repo.one!(topic_query(topic_id, forum_id))
Post
|> join(:inner, [p], _ in assoc(p, :topic))
|> join(:inner, [_p, t], _ in assoc(t, :forum))
|> where(destroyed_content: false)
|> where([_p, t], t.hidden_from_users == false and t.slug == ^topic_id)
|> where([_p, _t, f], f.access_level == "normal" and f.short_name == ^forum_id)
|> where([p], p.topic_position >= ^(25 * (page - 1)) and p.topic_position < ^(25 * page))
|> order_by(asc: :topic_position)
|> preload([:user, :topic])
|> preload([_p, t, _f], topic: t)
|> Repo.all()
render(conn, "index.json", posts: posts, total: hd(posts).topic.post_count) {posts, cursors} =
post_query(topic_id, forum_id)
|> where(
[posts: p],
p.topic_position >= ^(25 * (page - 1)) and p.topic_position < ^(25 * page)
)
|> Cursor.paginate([page_size: 25], [], asc: :topic_position)
render(conn, "index.json", cursors: cursors, posts: posts, total: topic.post_count)
end end
def show(conn, %{"forum_id" => forum_id, "topic_id" => topic_id, "id" => post_id}) do def show(conn, %{"forum_id" => forum_id, "topic_id" => topic_id, "id" => post_id}) do
post = post =
Post post_query(forum_id, topic_id)
|> join(:inner, [p], _ in assoc(p, :topic))
|> join(:inner, [_p, t], _ in assoc(t, :forum))
|> where(id: ^post_id) |> where(id: ^post_id)
|> where(destroyed_content: false)
|> where([_p, t], t.hidden_from_users == false and t.slug == ^topic_id)
|> where([_p, _t, f], f.access_level == "normal" and f.short_name == ^forum_id)
|> preload([:user, :topic])
|> Repo.one() |> Repo.one()
cond do cond do
@ -46,4 +53,27 @@ defmodule PhilomenaWeb.Api.Json.Forum.Topic.PostController do
render(conn, "show.json", post: post) render(conn, "show.json", post: post)
end end
end end
defp topic_query(topic_id, forum_id) do
Topic
|> from(as: :topic)
|> join(:inner, [topic: t], _ in assoc(t, :forum), as: :forum)
|> topic_conditions(topic_id, forum_id)
end
defp post_query(topic_id, forum_id) do
Post
|> from(as: :posts)
|> join(:inner, [posts: p], _ in assoc(p, :topic), as: :topic)
|> join(:inner, [topic: t], _ in assoc(t, :forum), as: :forum)
|> topic_conditions(topic_id, forum_id)
|> where([posts: p], p.destroyed_content == false)
|> preload([:user])
end
defp topic_conditions(queryable, topic_id, forum_id) do
queryable
|> where([topic: t], t.hidden_from_users == false and t.slug == ^topic_id)
|> where([forum: f], f.access_level == "normal" and f.short_name == ^forum_id)
end
end end

View file

@ -2,20 +2,24 @@ defmodule PhilomenaWeb.Api.Json.Forum.TopicController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias Philomena.Topics.Topic alias Philomena.Topics.Topic
alias PhilomenaQuery.Cursor
alias Philomena.Repo alias Philomena.Repo
import Ecto.Query import Ecto.Query
def index(conn, %{"forum_id" => id}) do def index(conn, %{"forum_id" => id} = params) do
topics = {topics, cursors} =
Topic Topic
|> join(:inner, [t], _ in assoc(t, :forum)) |> join(:inner, [t], _ in assoc(t, :forum))
|> where(hidden_from_users: false) |> where(hidden_from_users: false)
|> where([_t, f], f.access_level == "normal" and f.short_name == ^id) |> where([_t, f], f.access_level == "normal" and f.short_name == ^id)
|> order_by(desc: :sticky, desc: :last_replied_to_at)
|> preload([:user]) |> preload([:user])
|> Repo.paginate(conn.assigns.scrivener) |> Cursor.paginate(conn.assigns.scrivener, params["search_after"],
desc: :sticky,
desc: :last_replied_to_at,
desc: :slug
)
render(conn, "index.json", topics: topics, total: topics.total_entries) render(conn, "index.json", cursors: cursors, topics: topics, total: topics.total_entries)
end end
def show(conn, %{"forum_id" => forum_id, "id" => id}) do def show(conn, %{"forum_id" => forum_id, "id" => id}) do
@ -25,7 +29,6 @@ defmodule PhilomenaWeb.Api.Json.Forum.TopicController do
|> where(slug: ^id) |> where(slug: ^id)
|> where(hidden_from_users: false) |> where(hidden_from_users: false)
|> where([_t, f], f.access_level == "normal" and f.short_name == ^forum_id) |> where([_t, f], f.access_level == "normal" and f.short_name == ^forum_id)
|> order_by(desc: :sticky, desc: :last_replied_to_at)
|> preload([:user]) |> preload([:user])
|> Repo.one() |> Repo.one()

View file

@ -1,18 +1,21 @@
defmodule PhilomenaWeb.Api.Json.ForumController do defmodule PhilomenaWeb.Api.Json.ForumController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias PhilomenaQuery.Cursor
alias Philomena.Forums.Forum alias Philomena.Forums.Forum
alias Philomena.Repo alias Philomena.Repo
import Ecto.Query import Ecto.Query
def index(conn, _params) do def index(conn, params) do
forums = {forums, cursors} =
Forum Forum
|> where(access_level: "normal") |> where(access_level: "normal")
|> order_by(asc: :name) |> Cursor.paginate(conn.assigns.scrivener, params["search_after"],
|> Repo.paginate(conn.assigns.scrivener) asc: :name,
asc: :short_name
)
render(conn, forums: forums, total: forums.total_entries) render(conn, cursors: cursors, forums: forums, total: forums.total_entries)
end end
def show(conn, %{"id" => id}) do def show(conn, %{"id" => id}) do

View file

@ -1,6 +1,7 @@
defmodule PhilomenaWeb.Api.Json.Search.CommentController do defmodule PhilomenaWeb.Api.Json.Search.CommentController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias PhilomenaQuery.Cursor
alias PhilomenaQuery.Search alias PhilomenaQuery.Search
alias Philomena.Comments.Comment alias Philomena.Comments.Comment
alias Philomena.Comments.Query alias Philomena.Comments.Query
@ -12,7 +13,7 @@ defmodule PhilomenaWeb.Api.Json.Search.CommentController do
case Query.compile(params["q"], user: user) do case Query.compile(params["q"], user: user) do
{:ok, query} -> {:ok, query} ->
comments = {comments, cursors} =
Comment Comment
|> Search.search_definition( |> Search.search_definition(
%{ %{
@ -27,15 +28,19 @@ defmodule PhilomenaWeb.Api.Json.Search.CommentController do
} }
} }
}, },
sort: %{posted_at: :desc} sort: [%{posted_at: :desc}, %{id: :desc}]
}, },
conn.assigns.pagination conn.assigns.pagination
) )
|> Search.search_records(preload(Comment, [:image, :user])) |> Cursor.search_records(preload(Comment, [:image, :user]), params["search_after"])
conn conn
|> put_view(PhilomenaWeb.Api.Json.CommentView) |> put_view(PhilomenaWeb.Api.Json.CommentView)
|> render("index.json", comments: comments, total: comments.total_entries) |> render("index.json",
comments: comments,
cursors: cursors,
total: comments.total_entries
)
{:error, msg} -> {:error, msg} ->
conn conn

View file

@ -1,6 +1,7 @@
defmodule PhilomenaWeb.Api.Json.Search.FilterController do defmodule PhilomenaWeb.Api.Json.Search.FilterController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias PhilomenaQuery.Cursor
alias PhilomenaQuery.Search alias PhilomenaQuery.Search
alias Philomena.Filters.Filter alias Philomena.Filters.Filter
alias Philomena.Filters.Query alias Philomena.Filters.Query
@ -11,7 +12,7 @@ defmodule PhilomenaWeb.Api.Json.Search.FilterController do
case Query.compile(params["q"], user: user) do case Query.compile(params["q"], user: user) do
{:ok, query} -> {:ok, query} ->
filters = {filters, cursors} =
Filter Filter
|> Search.search_definition( |> Search.search_definition(
%{ %{
@ -36,11 +37,11 @@ defmodule PhilomenaWeb.Api.Json.Search.FilterController do
}, },
conn.assigns.pagination conn.assigns.pagination
) )
|> Search.search_records(preload(Filter, [:user])) |> Cursor.search_records(preload(Filter, [:user]), params["search_after"])
conn conn
|> put_view(PhilomenaWeb.Api.Json.FilterView) |> put_view(PhilomenaWeb.Api.Json.FilterView)
|> render("index.json", filters: filters, total: filters.total_entries) |> render("index.json", cursors: cursors, filters: filters, total: filters.total_entries)
{:error, msg} -> {:error, msg} ->
conn conn

View file

@ -1,6 +1,7 @@
defmodule PhilomenaWeb.Api.Json.Search.GalleryController do defmodule PhilomenaWeb.Api.Json.Search.GalleryController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias PhilomenaQuery.Cursor
alias PhilomenaQuery.Search alias PhilomenaQuery.Search
alias Philomena.Galleries.Gallery alias Philomena.Galleries.Gallery
alias Philomena.Galleries.Query alias Philomena.Galleries.Query
@ -9,20 +10,24 @@ defmodule PhilomenaWeb.Api.Json.Search.GalleryController do
def index(conn, params) do def index(conn, params) do
case Query.compile(params["q"]) do case Query.compile(params["q"]) do
{:ok, query} -> {:ok, query} ->
galleries = {galleries, cursors} =
Gallery Gallery
|> Search.search_definition( |> Search.search_definition(
%{ %{
query: query, query: query,
sort: %{created_at: :desc} sort: [%{created_at: :desc}, %{id: :desc}]
}, },
conn.assigns.pagination conn.assigns.pagination
) )
|> Search.search_records(preload(Gallery, [:creator])) |> Cursor.search_records(preload(Gallery, [:creator]), params["search_after"])
conn conn
|> put_view(PhilomenaWeb.Api.Json.GalleryView) |> put_view(PhilomenaWeb.Api.Json.GalleryView)
|> render("index.json", galleries: galleries, total: galleries.total_entries) |> render("index.json",
cursors: cursors,
galleries: galleries,
total: galleries.total_entries
)
{:error, msg} -> {:error, msg} ->
conn conn

View file

@ -2,7 +2,7 @@ defmodule PhilomenaWeb.Api.Json.Search.ImageController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias PhilomenaWeb.ImageLoader alias PhilomenaWeb.ImageLoader
alias PhilomenaQuery.Search alias PhilomenaQuery.Cursor
alias Philomena.Interactions alias Philomena.Interactions
alias Philomena.Images.Image alias Philomena.Images.Image
import Ecto.Query import Ecto.Query
@ -13,13 +13,14 @@ defmodule PhilomenaWeb.Api.Json.Search.ImageController do
case ImageLoader.search_string(conn, params["q"]) do case ImageLoader.search_string(conn, params["q"]) do
{:ok, {images, _tags}} -> {:ok, {images, _tags}} ->
images = Search.search_records(images, queryable) {images, cursors} = Cursor.search_records(images, queryable, params["search_after"])
interactions = Interactions.user_interactions(images, user) interactions = Interactions.user_interactions(images, user)
conn conn
|> put_view(PhilomenaWeb.Api.Json.ImageView) |> put_view(PhilomenaWeb.Api.Json.ImageView)
|> render("index.json", |> render("index.json",
images: images, images: images,
cursors: cursors,
total: images.total_entries, total: images.total_entries,
interactions: interactions interactions: interactions
) )

View file

@ -1,6 +1,7 @@
defmodule PhilomenaWeb.Api.Json.Search.PostController do defmodule PhilomenaWeb.Api.Json.Search.PostController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias PhilomenaQuery.Cursor
alias PhilomenaQuery.Search alias PhilomenaQuery.Search
alias Philomena.Posts.Post alias Philomena.Posts.Post
alias Philomena.Posts.Query alias Philomena.Posts.Query
@ -11,7 +12,7 @@ defmodule PhilomenaWeb.Api.Json.Search.PostController do
case Query.compile(params["q"], user: user) do case Query.compile(params["q"], user: user) do
{:ok, query} -> {:ok, query} ->
posts = {posts, cursors} =
Post Post
|> Search.search_definition( |> Search.search_definition(
%{ %{
@ -24,15 +25,15 @@ defmodule PhilomenaWeb.Api.Json.Search.PostController do
] ]
} }
}, },
sort: %{created_at: :desc} sort: [%{created_at: :desc}, %{id: :desc}]
}, },
conn.assigns.pagination conn.assigns.pagination
) )
|> Search.search_records(preload(Post, [:user, :topic])) |> Cursor.search_records(preload(Post, [:user, :topic]), params["search_after"])
conn conn
|> put_view(PhilomenaWeb.Api.Json.Forum.Topic.PostView) |> put_view(PhilomenaWeb.Api.Json.Forum.Topic.PostView)
|> render("index.json", posts: posts, total: posts.total_entries) |> render("index.json", cursors: cursors, posts: posts, total: posts.total_entries)
{:error, msg} -> {:error, msg} ->
conn conn

View file

@ -29,6 +29,7 @@ defmodule PhilomenaWeb.Api.Json.Search.ReverseController do
|> put_view(PhilomenaWeb.Api.Json.ImageView) |> put_view(PhilomenaWeb.Api.Json.ImageView)
|> render("index.json", |> render("index.json",
images: images, images: images,
cursors: %{},
total: total, total: total,
interactions: interactions interactions: interactions
) )

View file

@ -1,6 +1,7 @@
defmodule PhilomenaWeb.Api.Json.Search.TagController do defmodule PhilomenaWeb.Api.Json.Search.TagController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias PhilomenaQuery.Cursor
alias PhilomenaQuery.Search alias PhilomenaQuery.Search
alias Philomena.Tags.Tag alias Philomena.Tags.Tag
alias Philomena.Tags.Query alias Philomena.Tags.Query
@ -9,19 +10,20 @@ defmodule PhilomenaWeb.Api.Json.Search.TagController do
def index(conn, params) do def index(conn, params) do
case Query.compile(params["q"]) do case Query.compile(params["q"]) do
{:ok, query} -> {:ok, query} ->
tags = {tags, cursors} =
Tag Tag
|> Search.search_definition( |> Search.search_definition(
%{query: query, sort: %{images: :desc}}, %{query: query, sort: [%{images: :desc}, %{id: :desc}]},
conn.assigns.pagination conn.assigns.pagination
) )
|> Search.search_records( |> Cursor.search_records(
preload(Tag, [:aliased_tag, :aliases, :implied_tags, :implied_by_tags, :dnp_entries]) preload(Tag, [:aliased_tag, :aliases, :implied_tags, :implied_by_tags, :dnp_entries]),
params["search_after"]
) )
conn conn
|> put_view(PhilomenaWeb.Api.Json.TagView) |> put_view(PhilomenaWeb.Api.Json.TagView)
|> render("index.json", tags: tags, total: tags.total_entries) |> render("index.json", cursors: cursors, tags: tags, total: tags.total_entries)
{:error, msg} -> {:error, msg} ->
conn conn

View file

@ -80,7 +80,7 @@ defmodule PhilomenaWeb.ImageSorter do
end end
defp parse_sf(_params, sd, query) do defp parse_sf(_params, sd, query) do
%{query: query, sorts: [%{"first_seen_at" => sd}]} %{query: query, sorts: [%{"first_seen_at" => sd}, %{"id" => sd}]}
end end
defp random_query(seed, sd, query) do defp random_query(seed, sd, query) do

View file

@ -2,8 +2,9 @@ defmodule PhilomenaWeb.Api.Json.CommentView do
use PhilomenaWeb, :view use PhilomenaWeb, :view
alias PhilomenaWeb.UserAttributionView alias PhilomenaWeb.UserAttributionView
def render("index.json", %{comments: comments, total: total} = assigns) do def render("index.json", %{cursors: cursors, comments: comments, total: total} = assigns) do
%{ %{
cursors: cursors,
comments: render_many(comments, PhilomenaWeb.Api.Json.CommentView, "comment.json", assigns), comments: render_many(comments, PhilomenaWeb.Api.Json.CommentView, "comment.json", assigns),
total: total total: total
} }

View file

@ -1,17 +1,6 @@
defmodule PhilomenaWeb.Api.Json.DnpView do defmodule PhilomenaWeb.Api.Json.DnpView do
use PhilomenaWeb, :view use PhilomenaWeb, :view
def render("index.json", %{dnps: dnp, total: total} = assigns) do
%{
dnps: render_many(dnp, PhilomenaWeb.Api.Json.DnpView, "dnp.json", assigns),
total: total
}
end
def render("show.json", %{dnp: dnp} = assigns) do
%{dnp: render_one(dnp, PhilomenaWeb.Api.Json.DnpView, "dnp.json", assigns)}
end
def render("dnp.json", %{dnp: dnp}) do def render("dnp.json", %{dnp: dnp}) do
%{ %{
id: dnp.id, id: dnp.id,

View file

@ -1,8 +1,9 @@
defmodule PhilomenaWeb.Api.Json.FilterView do defmodule PhilomenaWeb.Api.Json.FilterView do
use PhilomenaWeb, :view use PhilomenaWeb, :view
def render("index.json", %{filters: filters, total: total} = assigns) do def render("index.json", %{cursors: cursors, filters: filters, total: total} = assigns) do
%{ %{
cursors: cursors,
filters: render_many(filters, PhilomenaWeb.Api.Json.FilterView, "filter.json", assigns), filters: render_many(filters, PhilomenaWeb.Api.Json.FilterView, "filter.json", assigns),
total: total total: total
} }

View file

@ -2,8 +2,9 @@ defmodule PhilomenaWeb.Api.Json.Forum.Topic.PostView do
use PhilomenaWeb, :view use PhilomenaWeb, :view
alias PhilomenaWeb.UserAttributionView alias PhilomenaWeb.UserAttributionView
def render("index.json", %{posts: posts, total: total} = assigns) do def render("index.json", %{cursors: cursors, posts: posts, total: total} = assigns) do
%{ %{
cursors: cursors,
posts: render_many(posts, PhilomenaWeb.Api.Json.Forum.Topic.PostView, "post.json", assigns), posts: render_many(posts, PhilomenaWeb.Api.Json.Forum.Topic.PostView, "post.json", assigns),
total: total total: total
} }

View file

@ -2,8 +2,9 @@ defmodule PhilomenaWeb.Api.Json.Forum.TopicView do
use PhilomenaWeb, :view use PhilomenaWeb, :view
alias PhilomenaWeb.UserAttributionView alias PhilomenaWeb.UserAttributionView
def render("index.json", %{topics: topics, total: total} = assigns) do def render("index.json", %{cursors: cursors, topics: topics, total: total} = assigns) do
%{ %{
cursors: cursors,
topics: render_many(topics, PhilomenaWeb.Api.Json.Forum.TopicView, "topic.json", assigns), topics: render_many(topics, PhilomenaWeb.Api.Json.Forum.TopicView, "topic.json", assigns),
total: total total: total
} }
@ -15,6 +16,7 @@ defmodule PhilomenaWeb.Api.Json.Forum.TopicView do
def render("topic.json", %{topic: %{hidden_from_users: true}}) do def render("topic.json", %{topic: %{hidden_from_users: true}}) do
%{ %{
id: nil,
slug: nil, slug: nil,
title: nil, title: nil,
post_count: nil, post_count: nil,
@ -29,6 +31,7 @@ defmodule PhilomenaWeb.Api.Json.Forum.TopicView do
def render("topic.json", %{topic: topic}) do def render("topic.json", %{topic: topic}) do
%{ %{
id: topic.id,
slug: topic.slug, slug: topic.slug,
title: topic.title, title: topic.title,
post_count: topic.post_count, post_count: topic.post_count,

View file

@ -1,8 +1,9 @@
defmodule PhilomenaWeb.Api.Json.ForumView do defmodule PhilomenaWeb.Api.Json.ForumView do
use PhilomenaWeb, :view use PhilomenaWeb, :view
def render("index.json", %{forums: forums, total: total} = assigns) do def render("index.json", %{cursors: cursors, forums: forums, total: total} = assigns) do
%{ %{
cursors: cursors,
forums: render_many(forums, PhilomenaWeb.Api.Json.ForumView, "forum.json", assigns), forums: render_many(forums, PhilomenaWeb.Api.Json.ForumView, "forum.json", assigns),
total: total total: total
} }
@ -14,6 +15,7 @@ defmodule PhilomenaWeb.Api.Json.ForumView do
def render("forum.json", %{forum: %{access_level: "normal"} = forum}) do def render("forum.json", %{forum: %{access_level: "normal"} = forum}) do
%{ %{
id: forum.id,
name: forum.name, name: forum.name,
short_name: forum.short_name, short_name: forum.short_name,
description: forum.description, description: forum.description,

View file

@ -1,8 +1,9 @@
defmodule PhilomenaWeb.Api.Json.GalleryView do defmodule PhilomenaWeb.Api.Json.GalleryView do
use PhilomenaWeb, :view use PhilomenaWeb, :view
def render("index.json", %{galleries: galleries, total: total} = assigns) do def render("index.json", %{cursors: cursors, galleries: galleries, total: total} = assigns) do
%{ %{
cursors: cursors,
galleries: galleries:
render_many(galleries, PhilomenaWeb.Api.Json.GalleryView, "gallery.json", assigns), render_many(galleries, PhilomenaWeb.Api.Json.GalleryView, "gallery.json", assigns),
total: total total: total

View file

@ -2,8 +2,12 @@ defmodule PhilomenaWeb.Api.Json.ImageView do
use PhilomenaWeb, :view use PhilomenaWeb, :view
alias PhilomenaWeb.ImageView alias PhilomenaWeb.ImageView
def render("index.json", %{images: images, interactions: interactions, total: total} = assigns) do def render(
"index.json",
%{cursors: cursors, images: images, interactions: interactions, total: total} = assigns
) do
%{ %{
cursors: cursors,
images: render_many(images, PhilomenaWeb.Api.Json.ImageView, "image.json", assigns), images: render_many(images, PhilomenaWeb.Api.Json.ImageView, "image.json", assigns),
interactions: interactions, interactions: interactions,
total: total total: total

View file

@ -1,8 +1,9 @@
defmodule PhilomenaWeb.Api.Json.TagView do defmodule PhilomenaWeb.Api.Json.TagView do
use PhilomenaWeb, :view use PhilomenaWeb, :view
def render("index.json", %{tags: tags, total: total} = assigns) do def render("index.json", %{cursors: cursors, tags: tags, total: total} = assigns) do
%{ %{
cursors: cursors,
tags: render_many(tags, PhilomenaWeb.Api.Json.TagView, "tag.json", assigns), tags: render_many(tags, PhilomenaWeb.Api.Json.TagView, "tag.json", assigns),
total: total total: total
} }