diff --git a/lib/philomena_query/cursor.ex b/lib/philomena_query/cursor.ex new file mode 100644 index 00000000..6f721a41 --- /dev/null +++ b/lib/philomena_query/cursor.ex @@ -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 diff --git a/lib/philomena_web/controllers/api/json/filter/system_filter_controller.ex b/lib/philomena_web/controllers/api/json/filter/system_filter_controller.ex index 6fbbfb30..0eed1992 100755 --- a/lib/philomena_web/controllers/api/json/filter/system_filter_controller.ex +++ b/lib/philomena_web/controllers/api/json/filter/system_filter_controller.ex @@ -2,18 +2,21 @@ defmodule PhilomenaWeb.Api.Json.Filter.SystemFilterController do use PhilomenaWeb, :controller alias Philomena.Filters.Filter - alias Philomena.Repo + alias PhilomenaQuery.Cursor import Ecto.Query - def index(conn, _params) do - system_filters = + def index(conn, params) do + {system_filters, cursors} = Filter |> where(system: true) - |> order_by(asc: :id) - |> Repo.paginate(conn.assigns.scrivener) + |> Cursor.paginate(conn.assigns.scrivener, params["search_after"], asc: :id) conn |> 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 diff --git a/lib/philomena_web/controllers/api/json/filter/user_filter_controller.ex b/lib/philomena_web/controllers/api/json/filter/user_filter_controller.ex index 5d7eee7b..77b0d600 100755 --- a/lib/philomena_web/controllers/api/json/filter/user_filter_controller.ex +++ b/lib/philomena_web/controllers/api/json/filter/user_filter_controller.ex @@ -2,10 +2,10 @@ defmodule PhilomenaWeb.Api.Json.Filter.UserFilterController do use PhilomenaWeb, :controller alias Philomena.Filters.Filter - alias Philomena.Repo + alias PhilomenaQuery.Cursor import Ecto.Query - def index(conn, _params) do + def index(conn, params) do user = conn.assigns.current_user case user do @@ -15,15 +15,18 @@ defmodule PhilomenaWeb.Api.Json.Filter.UserFilterController do |> text("") _ -> - user_filters = + {user_filters, cursors} = Filter |> where(user_id: ^user.id) - |> order_by(asc: :id) - |> Repo.paginate(conn.assigns.scrivener) + |> Cursor.paginate(conn.assigns.scrivener, params["search_after"], asc: :id) conn |> 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 diff --git a/lib/philomena_web/controllers/api/json/forum/topic/post_controller.ex b/lib/philomena_web/controllers/api/json/forum/topic/post_controller.ex index e33f08d8..cbae2f31 100644 --- a/lib/philomena_web/controllers/api/json/forum/topic/post_controller.ex +++ b/lib/philomena_web/controllers/api/json/forum/topic/post_controller.ex @@ -1,39 +1,46 @@ defmodule PhilomenaWeb.Api.Json.Forum.Topic.PostController do use PhilomenaWeb, :controller + alias Philomena.Topics.Topic alias Philomena.Posts.Post + alias PhilomenaQuery.Cursor alias Philomena.Repo 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 page = conn.assigns.pagination.page_number - posts = - 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() + topic = Repo.one!(topic_query(topic_id, forum_id)) - 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 def show(conn, %{"forum_id" => forum_id, "topic_id" => topic_id, "id" => post_id}) do post = - Post - |> join(:inner, [p], _ in assoc(p, :topic)) - |> join(:inner, [_p, t], _ in assoc(t, :forum)) + post_query(forum_id, topic_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() cond do @@ -46,4 +53,27 @@ defmodule PhilomenaWeb.Api.Json.Forum.Topic.PostController do render(conn, "show.json", post: post) 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 diff --git a/lib/philomena_web/controllers/api/json/forum/topic_controller.ex b/lib/philomena_web/controllers/api/json/forum/topic_controller.ex index 56730f65..fb7fde49 100644 --- a/lib/philomena_web/controllers/api/json/forum/topic_controller.ex +++ b/lib/philomena_web/controllers/api/json/forum/topic_controller.ex @@ -2,20 +2,24 @@ defmodule PhilomenaWeb.Api.Json.Forum.TopicController do use PhilomenaWeb, :controller alias Philomena.Topics.Topic + alias PhilomenaQuery.Cursor alias Philomena.Repo import Ecto.Query - def index(conn, %{"forum_id" => id}) do - topics = + def index(conn, %{"forum_id" => id} = params) do + {topics, cursors} = Topic |> join(:inner, [t], _ in assoc(t, :forum)) |> where(hidden_from_users: false) |> where([_t, f], f.access_level == "normal" and f.short_name == ^id) - |> order_by(desc: :sticky, desc: :last_replied_to_at) |> 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 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(hidden_from_users: false) |> where([_t, f], f.access_level == "normal" and f.short_name == ^forum_id) - |> order_by(desc: :sticky, desc: :last_replied_to_at) |> preload([:user]) |> Repo.one() diff --git a/lib/philomena_web/controllers/api/json/forum_controller.ex b/lib/philomena_web/controllers/api/json/forum_controller.ex index 4ef39af5..e6cf7543 100644 --- a/lib/philomena_web/controllers/api/json/forum_controller.ex +++ b/lib/philomena_web/controllers/api/json/forum_controller.ex @@ -1,18 +1,21 @@ defmodule PhilomenaWeb.Api.Json.ForumController do use PhilomenaWeb, :controller + alias PhilomenaQuery.Cursor alias Philomena.Forums.Forum alias Philomena.Repo import Ecto.Query - def index(conn, _params) do - forums = + def index(conn, params) do + {forums, cursors} = Forum |> where(access_level: "normal") - |> order_by(asc: :name) - |> Repo.paginate(conn.assigns.scrivener) + |> Cursor.paginate(conn.assigns.scrivener, params["search_after"], + asc: :name, + asc: :short_name + ) - render(conn, forums: forums, total: forums.total_entries) + render(conn, cursors: cursors, forums: forums, total: forums.total_entries) end def show(conn, %{"id" => id}) do diff --git a/lib/philomena_web/controllers/api/json/search/comment_controller.ex b/lib/philomena_web/controllers/api/json/search/comment_controller.ex index 6942a4ff..b974fc48 100644 --- a/lib/philomena_web/controllers/api/json/search/comment_controller.ex +++ b/lib/philomena_web/controllers/api/json/search/comment_controller.ex @@ -1,6 +1,7 @@ defmodule PhilomenaWeb.Api.Json.Search.CommentController do use PhilomenaWeb, :controller + alias PhilomenaQuery.Cursor alias PhilomenaQuery.Search alias Philomena.Comments.Comment alias Philomena.Comments.Query @@ -12,7 +13,7 @@ defmodule PhilomenaWeb.Api.Json.Search.CommentController do case Query.compile(params["q"], user: user) do {:ok, query} -> - comments = + {comments, cursors} = Comment |> 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 ) - |> Search.search_records(preload(Comment, [:image, :user])) + |> Cursor.search_records(preload(Comment, [:image, :user]), params["search_after"]) conn |> 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} -> conn diff --git a/lib/philomena_web/controllers/api/json/search/filter_controller.ex b/lib/philomena_web/controllers/api/json/search/filter_controller.ex index 7c4f81b5..f6757f62 100644 --- a/lib/philomena_web/controllers/api/json/search/filter_controller.ex +++ b/lib/philomena_web/controllers/api/json/search/filter_controller.ex @@ -1,6 +1,7 @@ defmodule PhilomenaWeb.Api.Json.Search.FilterController do use PhilomenaWeb, :controller + alias PhilomenaQuery.Cursor alias PhilomenaQuery.Search alias Philomena.Filters.Filter alias Philomena.Filters.Query @@ -11,7 +12,7 @@ defmodule PhilomenaWeb.Api.Json.Search.FilterController do case Query.compile(params["q"], user: user) do {:ok, query} -> - filters = + {filters, cursors} = Filter |> Search.search_definition( %{ @@ -36,11 +37,11 @@ defmodule PhilomenaWeb.Api.Json.Search.FilterController do }, conn.assigns.pagination ) - |> Search.search_records(preload(Filter, [:user])) + |> Cursor.search_records(preload(Filter, [:user]), params["search_after"]) conn |> 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} -> conn diff --git a/lib/philomena_web/controllers/api/json/search/gallery_controller.ex b/lib/philomena_web/controllers/api/json/search/gallery_controller.ex index e1b999bb..b63691a9 100644 --- a/lib/philomena_web/controllers/api/json/search/gallery_controller.ex +++ b/lib/philomena_web/controllers/api/json/search/gallery_controller.ex @@ -1,6 +1,7 @@ defmodule PhilomenaWeb.Api.Json.Search.GalleryController do use PhilomenaWeb, :controller + alias PhilomenaQuery.Cursor alias PhilomenaQuery.Search alias Philomena.Galleries.Gallery alias Philomena.Galleries.Query @@ -9,20 +10,24 @@ defmodule PhilomenaWeb.Api.Json.Search.GalleryController do def index(conn, params) do case Query.compile(params["q"]) do {:ok, query} -> - galleries = + {galleries, cursors} = Gallery |> Search.search_definition( %{ query: query, - sort: %{created_at: :desc} + sort: [%{created_at: :desc}, %{id: :desc}] }, conn.assigns.pagination ) - |> Search.search_records(preload(Gallery, [:creator])) + |> Cursor.search_records(preload(Gallery, [:creator]), params["search_after"]) conn |> 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} -> conn diff --git a/lib/philomena_web/controllers/api/json/search/image_controller.ex b/lib/philomena_web/controllers/api/json/search/image_controller.ex index 109e7abe..a32ea68d 100644 --- a/lib/philomena_web/controllers/api/json/search/image_controller.ex +++ b/lib/philomena_web/controllers/api/json/search/image_controller.ex @@ -2,7 +2,7 @@ defmodule PhilomenaWeb.Api.Json.Search.ImageController do use PhilomenaWeb, :controller alias PhilomenaWeb.ImageLoader - alias PhilomenaQuery.Search + alias PhilomenaQuery.Cursor alias Philomena.Interactions alias Philomena.Images.Image import Ecto.Query @@ -13,13 +13,14 @@ defmodule PhilomenaWeb.Api.Json.Search.ImageController do case ImageLoader.search_string(conn, params["q"]) do {: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) conn |> put_view(PhilomenaWeb.Api.Json.ImageView) |> render("index.json", images: images, + cursors: cursors, total: images.total_entries, interactions: interactions ) diff --git a/lib/philomena_web/controllers/api/json/search/post_controller.ex b/lib/philomena_web/controllers/api/json/search/post_controller.ex index c305de12..6fbf4f1e 100644 --- a/lib/philomena_web/controllers/api/json/search/post_controller.ex +++ b/lib/philomena_web/controllers/api/json/search/post_controller.ex @@ -1,6 +1,7 @@ defmodule PhilomenaWeb.Api.Json.Search.PostController do use PhilomenaWeb, :controller + alias PhilomenaQuery.Cursor alias PhilomenaQuery.Search alias Philomena.Posts.Post alias Philomena.Posts.Query @@ -11,7 +12,7 @@ defmodule PhilomenaWeb.Api.Json.Search.PostController do case Query.compile(params["q"], user: user) do {:ok, query} -> - posts = + {posts, cursors} = Post |> 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 ) - |> Search.search_records(preload(Post, [:user, :topic])) + |> Cursor.search_records(preload(Post, [:user, :topic]), params["search_after"]) conn |> 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} -> conn diff --git a/lib/philomena_web/controllers/api/json/search/reverse_controller.ex b/lib/philomena_web/controllers/api/json/search/reverse_controller.ex index 4abe7560..10c4f207 100644 --- a/lib/philomena_web/controllers/api/json/search/reverse_controller.ex +++ b/lib/philomena_web/controllers/api/json/search/reverse_controller.ex @@ -29,6 +29,7 @@ defmodule PhilomenaWeb.Api.Json.Search.ReverseController do |> put_view(PhilomenaWeb.Api.Json.ImageView) |> render("index.json", images: images, + cursors: %{}, total: total, interactions: interactions ) diff --git a/lib/philomena_web/controllers/api/json/search/tag_controller.ex b/lib/philomena_web/controllers/api/json/search/tag_controller.ex index b860cf46..92577849 100644 --- a/lib/philomena_web/controllers/api/json/search/tag_controller.ex +++ b/lib/philomena_web/controllers/api/json/search/tag_controller.ex @@ -1,6 +1,7 @@ defmodule PhilomenaWeb.Api.Json.Search.TagController do use PhilomenaWeb, :controller + alias PhilomenaQuery.Cursor alias PhilomenaQuery.Search alias Philomena.Tags.Tag alias Philomena.Tags.Query @@ -9,19 +10,20 @@ defmodule PhilomenaWeb.Api.Json.Search.TagController do def index(conn, params) do case Query.compile(params["q"]) do {:ok, query} -> - tags = + {tags, cursors} = Tag |> Search.search_definition( - %{query: query, sort: %{images: :desc}}, + %{query: query, sort: [%{images: :desc}, %{id: :desc}]}, conn.assigns.pagination ) - |> Search.search_records( - preload(Tag, [:aliased_tag, :aliases, :implied_tags, :implied_by_tags, :dnp_entries]) + |> Cursor.search_records( + preload(Tag, [:aliased_tag, :aliases, :implied_tags, :implied_by_tags, :dnp_entries]), + params["search_after"] ) conn |> 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} -> conn diff --git a/lib/philomena_web/image_sorter.ex b/lib/philomena_web/image_sorter.ex index ed422288..564d3781 100644 --- a/lib/philomena_web/image_sorter.ex +++ b/lib/philomena_web/image_sorter.ex @@ -80,7 +80,7 @@ defmodule PhilomenaWeb.ImageSorter do end defp parse_sf(_params, sd, query) do - %{query: query, sorts: [%{"first_seen_at" => sd}]} + %{query: query, sorts: [%{"first_seen_at" => sd}, %{"id" => sd}]} end defp random_query(seed, sd, query) do diff --git a/lib/philomena_web/views/api/json/comment_view.ex b/lib/philomena_web/views/api/json/comment_view.ex index 5d80b42b..2eb065f2 100644 --- a/lib/philomena_web/views/api/json/comment_view.ex +++ b/lib/philomena_web/views/api/json/comment_view.ex @@ -2,8 +2,9 @@ defmodule PhilomenaWeb.Api.Json.CommentView do use PhilomenaWeb, :view 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), total: total } diff --git a/lib/philomena_web/views/api/json/dnp_view.ex b/lib/philomena_web/views/api/json/dnp_view.ex index ad07db2f..9395bf06 100755 --- a/lib/philomena_web/views/api/json/dnp_view.ex +++ b/lib/philomena_web/views/api/json/dnp_view.ex @@ -1,17 +1,6 @@ defmodule PhilomenaWeb.Api.Json.DnpView do 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 %{ id: dnp.id, diff --git a/lib/philomena_web/views/api/json/filter_view.ex b/lib/philomena_web/views/api/json/filter_view.ex index bf9294d6..a83e85fa 100644 --- a/lib/philomena_web/views/api/json/filter_view.ex +++ b/lib/philomena_web/views/api/json/filter_view.ex @@ -1,8 +1,9 @@ defmodule PhilomenaWeb.Api.Json.FilterView do 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), total: total } diff --git a/lib/philomena_web/views/api/json/forum/topic/post_view.ex b/lib/philomena_web/views/api/json/forum/topic/post_view.ex index 4d6ecdcb..9db3665a 100644 --- a/lib/philomena_web/views/api/json/forum/topic/post_view.ex +++ b/lib/philomena_web/views/api/json/forum/topic/post_view.ex @@ -2,8 +2,9 @@ defmodule PhilomenaWeb.Api.Json.Forum.Topic.PostView do use PhilomenaWeb, :view 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), total: total } diff --git a/lib/philomena_web/views/api/json/forum/topic_view.ex b/lib/philomena_web/views/api/json/forum/topic_view.ex index 564eb5f2..e1428fc4 100644 --- a/lib/philomena_web/views/api/json/forum/topic_view.ex +++ b/lib/philomena_web/views/api/json/forum/topic_view.ex @@ -2,8 +2,9 @@ defmodule PhilomenaWeb.Api.Json.Forum.TopicView do use PhilomenaWeb, :view 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), total: total } @@ -15,6 +16,7 @@ defmodule PhilomenaWeb.Api.Json.Forum.TopicView do def render("topic.json", %{topic: %{hidden_from_users: true}}) do %{ + id: nil, slug: nil, title: nil, post_count: nil, @@ -29,6 +31,7 @@ defmodule PhilomenaWeb.Api.Json.Forum.TopicView do def render("topic.json", %{topic: topic}) do %{ + id: topic.id, slug: topic.slug, title: topic.title, post_count: topic.post_count, diff --git a/lib/philomena_web/views/api/json/forum_view.ex b/lib/philomena_web/views/api/json/forum_view.ex index f6995d1b..5ede57f2 100644 --- a/lib/philomena_web/views/api/json/forum_view.ex +++ b/lib/philomena_web/views/api/json/forum_view.ex @@ -1,8 +1,9 @@ defmodule PhilomenaWeb.Api.Json.ForumView do 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), total: total } @@ -14,6 +15,7 @@ defmodule PhilomenaWeb.Api.Json.ForumView do def render("forum.json", %{forum: %{access_level: "normal"} = forum}) do %{ + id: forum.id, name: forum.name, short_name: forum.short_name, description: forum.description, diff --git a/lib/philomena_web/views/api/json/gallery_view.ex b/lib/philomena_web/views/api/json/gallery_view.ex index d49c1236..7ea4b3d0 100644 --- a/lib/philomena_web/views/api/json/gallery_view.ex +++ b/lib/philomena_web/views/api/json/gallery_view.ex @@ -1,8 +1,9 @@ defmodule PhilomenaWeb.Api.Json.GalleryView do 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: render_many(galleries, PhilomenaWeb.Api.Json.GalleryView, "gallery.json", assigns), total: total diff --git a/lib/philomena_web/views/api/json/image_view.ex b/lib/philomena_web/views/api/json/image_view.ex index f72a676e..79312ee4 100644 --- a/lib/philomena_web/views/api/json/image_view.ex +++ b/lib/philomena_web/views/api/json/image_view.ex @@ -2,8 +2,12 @@ defmodule PhilomenaWeb.Api.Json.ImageView do use PhilomenaWeb, :view 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), interactions: interactions, total: total diff --git a/lib/philomena_web/views/api/json/tag_view.ex b/lib/philomena_web/views/api/json/tag_view.ex index 8aaa6248..626365f1 100644 --- a/lib/philomena_web/views/api/json/tag_view.ex +++ b/lib/philomena_web/views/api/json/tag_view.ex @@ -1,8 +1,9 @@ defmodule PhilomenaWeb.Api.Json.TagView do 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), total: total }