From 48eb72cd4cb3198595f3e4dffa2070a8c5c7fa6f Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 14 Dec 2018 11:23:36 +0100 Subject: [PATCH] Add pagination to events, groups, partipants to an event and categories lists --- lib/mobilizon/actors/actor.ex | 20 +++++------ lib/mobilizon/actors/actors.ex | 19 +++++++---- lib/mobilizon/ecto.ex | 34 +++++++++++++++++++ lib/mobilizon/events/events.ex | 42 ++++++++++-------------- lib/mobilizon/events/tag.ex | 2 +- lib/mobilizon/slug.ex | 17 ---------- lib/mobilizon_web/resolvers/category.ex | 4 +-- lib/mobilizon_web/resolvers/event.ex | 8 ++--- lib/mobilizon_web/resolvers/group.ex | 4 +-- lib/mobilizon_web/schema.ex | 10 +++++- lib/service/activity_pub/activity_pub.ex | 4 ++- 11 files changed, 92 insertions(+), 72 deletions(-) create mode 100644 lib/mobilizon/ecto.ex delete mode 100644 lib/mobilizon/slug.ex diff --git a/lib/mobilizon/actors/actor.ex b/lib/mobilizon/actors/actor.ex index 0d3e33767..be10814e2 100644 --- a/lib/mobilizon/actors/actor.ex +++ b/lib/mobilizon/actors/actor.ex @@ -20,11 +20,13 @@ defmodule Mobilizon.Actors.Actor do """ use Ecto.Schema import Ecto.Changeset + alias Mobilizon.Actors alias Mobilizon.Actors.{Actor, User, Follower, Member} alias Mobilizon.Events.Event import Ecto.Query + import Mobilizon.Ecto alias Mobilizon.Repo require Logger @@ -232,18 +234,15 @@ defmodule Mobilizon.Actors.Actor do If actor A and C both follow actor B, actor B's followers are A and C """ - def get_followers(%Actor{id: actor_id} = _actor, page \\ 1, limit \\ 10) do - start = (page - 1) * limit - + def get_followers(%Actor{id: actor_id} = _actor, page \\ nil, limit \\ nil) do Repo.all( from( a in Actor, join: f in Follower, on: a.id == f.actor_id, - where: f.target_actor_id == ^actor_id, - limit: ^limit, - offset: ^start + where: f.target_actor_id == ^actor_id ) + |> paginate(page, limit) ) end @@ -252,18 +251,15 @@ defmodule Mobilizon.Actors.Actor do If actor A follows actor B and C, actor A's followings are B and B """ - def get_followings(%Actor{id: actor_id} = _actor, page \\ 1, limit \\ 10) do - start = (page - 1) * limit - + def get_followings(%Actor{id: actor_id} = _actor, page \\ nil, limit \\ nil) do Repo.all( from( a in Actor, join: f in Follower, on: a.id == f.target_actor_id, - where: f.actor_id == ^actor_id, - limit: ^limit, - offset: ^start + where: f.actor_id == ^actor_id ) + |> paginate(page, limit) ) end diff --git a/lib/mobilizon/actors/actors.ex b/lib/mobilizon/actors/actors.ex index bc0b5b078..f4d69c94d 100644 --- a/lib/mobilizon/actors/actors.ex +++ b/lib/mobilizon/actors/actors.ex @@ -4,6 +4,8 @@ defmodule Mobilizon.Actors do """ import Ecto.Query, warn: false + import Mobilizon.Ecto + alias Mobilizon.Repo alias Mobilizon.Actors.{Actor, Bot, Member, Follower, User} @@ -150,8 +152,14 @@ defmodule Mobilizon.Actors do @doc """ List the groups """ - def list_groups do - Repo.all(from(a in Actor, where: a.type == ^:Group)) + def list_groups(page \\ nil, limit \\ nil) do + Repo.all( + from( + a in Actor, + where: a.type == ^:Group + ) + |> paginate(page, limit) + ) end def get_group_by_name(name) do @@ -446,21 +454,18 @@ defmodule Mobilizon.Actors do Find actors by their name or displayed name """ @spec find_actors_by_username_or_name(String.t(), integer(), integer()) :: list(Actor.t()) - def find_actors_by_username_or_name(username, page \\ 1, limit \\ 10) + def find_actors_by_username_or_name(username, page \\ nil, limit \\ nil) def find_actors_by_username_or_name("", _page, _limit), do: [] def find_actors_by_username_or_name(username, page, limit) do - start = (page - 1) * limit - Repo.all( from( a in Actor, - limit: ^limit, - offset: ^start, where: ilike(a.preferred_username, ^like_sanitize(username)) or ilike(a.name, ^like_sanitize(username)) ) + |> paginate(page, limit) ) end diff --git a/lib/mobilizon/ecto.ex b/lib/mobilizon/ecto.ex new file mode 100644 index 000000000..b5ee0d4f7 --- /dev/null +++ b/lib/mobilizon/ecto.ex @@ -0,0 +1,34 @@ +defmodule Mobilizon.Ecto do + @moduledoc """ + Mobilizon Ecto utils + """ + + import Ecto.Query, warn: false + + @doc """ + Add limit and offset to the query + """ + def paginate(query, page \\ 1, size \\ 10) + def paginate(query, page, _size) when is_nil(page), do: paginate(query) + def paginate(query, page, size) when is_nil(size), do: paginate(query, page) + + def paginate(query, page, size) do + from(query, + limit: ^size, + offset: ^((page - 1) * size) + ) + end + + def increment_slug(slug) do + case List.pop_at(String.split(slug, "-"), -1) do + {nil, _} -> + slug + + {suffix, slug_parts} -> + case Integer.parse(suffix) do + {id, _} -> Enum.join(slug_parts, "-") <> "-" <> Integer.to_string(id + 1) + :error -> slug <> "-1" + end + end + end +end diff --git a/lib/mobilizon/events/events.ex b/lib/mobilizon/events/events.ex index 7d0aa45e2..66a9730f6 100644 --- a/lib/mobilizon/events/events.ex +++ b/lib/mobilizon/events/events.ex @@ -4,6 +4,7 @@ defmodule Mobilizon.Events do """ import Ecto.Query, warn: false + import Mobilizon.Ecto alias Mobilizon.Repo alias Mobilizon.Events.{Event, Comment, Participant} @@ -18,16 +19,12 @@ defmodule Mobilizon.Events do queryable end - def get_events_for_actor(%Actor{id: actor_id} = _actor, page \\ 1, limit \\ 10) do - start = (page - 1) * limit - + def get_events_for_actor(%Actor{id: actor_id} = _actor, page \\ nil, limit \\ nil) do query = from( e in Event, where: e.organizer_actor_id == ^actor_id, - limit: ^limit, order_by: [desc: :id], - offset: ^start, preload: [ :organizer_actor, :category, @@ -38,6 +35,7 @@ defmodule Mobilizon.Events do :physical_address ] ) + |> paginate(page, limit) events = Repo.all(query) @@ -186,15 +184,10 @@ defmodule Mobilizon.Events do [%Event{}, ...] """ - def list_events(page \\ 1, limit \\ 10) do - start = (page - 1) * limit - + def list_events(page \\ nil, limit \\ nil) do query = - from(e in Event, - limit: ^limit, - offset: ^start, - preload: [:organizer_actor] - ) + from(e in Event, preload: [:organizer_actor]) + |> paginate(page, limit) Repo.all(query) end @@ -202,20 +195,18 @@ defmodule Mobilizon.Events do @doc """ Find events by name """ - def find_events_by_name(name, page \\ 1, limit \\ 10) + def find_events_by_name(name, page \\ nil, limit \\ nil) def find_events_by_name("", page, limit), do: list_events(page, limit) def find_events_by_name(name, page, limit) do name = String.trim(name) - start = (page - 1) * limit query = from(e in Event, - limit: ^limit, - offset: ^start, where: ilike(e.title, ^like_sanitize(name)), preload: [:organizer_actor] ) + |> paginate(page, limit) Repo.all(query) end @@ -309,8 +300,11 @@ defmodule Mobilizon.Events do [%Category{}, ...] """ - def list_categories do - Repo.all(Category) + def list_categories(page \\ nil, limit \\ nil) do + Repo.all( + Category + |> paginate(page, limit) + ) end @doc """ @@ -519,7 +513,7 @@ defmodule Mobilizon.Events do [%Participant{}, ...] """ - def list_participants_for_event(uuid) do + def list_participants_for_event(uuid, page \\ nil, limit \\ nil) do Repo.all( from( p in Participant, @@ -528,6 +522,7 @@ defmodule Mobilizon.Events do where: e.uuid == ^uuid, preload: [:actor] ) + |> paginate(page, limit) ) end @@ -846,16 +841,12 @@ defmodule Mobilizon.Events do Repo.all(Comment) end - def get_comments_for_actor(%Actor{id: actor_id}, page \\ 1, limit \\ 10) do - start = (page - 1) * limit - + def get_comments_for_actor(%Actor{id: actor_id}, page \\ nil, limit \\ nil) do query = from( c in Comment, where: c.actor_id == ^actor_id, - limit: ^limit, order_by: [desc: :id], - offset: ^start, preload: [ :actor, :in_reply_to_comment, @@ -863,6 +854,7 @@ defmodule Mobilizon.Events do :event ] ) + |> paginate(page, limit) comments = Repo.all(query) diff --git a/lib/mobilizon/events/tag.ex b/lib/mobilizon/events/tag.ex index 967015351..79ac2b523 100644 --- a/lib/mobilizon/events/tag.ex +++ b/lib/mobilizon/events/tag.ex @@ -25,7 +25,7 @@ defmodule Mobilizon.Events.Tag.TitleSlug do _tag -> slug - |> Mobilizon.Slug.increment_slug() + |> Mobilizon.Ecto.increment_slug() |> build_unique_slug(changeset) end end diff --git a/lib/mobilizon/slug.ex b/lib/mobilizon/slug.ex deleted file mode 100644 index 857590634..000000000 --- a/lib/mobilizon/slug.ex +++ /dev/null @@ -1,17 +0,0 @@ -defmodule Mobilizon.Slug do - @moduledoc """ - Common functions for slug generation - """ - def increment_slug(slug) do - case List.pop_at(String.split(slug, "-"), -1) do - {nil, _} -> - slug - - {suffix, slug_parts} -> - case Integer.parse(suffix) do - {id, _} -> Enum.join(slug_parts, "-") <> "-" <> Integer.to_string(id + 1) - :error -> slug <> "-1" - end - end - end -end diff --git a/lib/mobilizon_web/resolvers/category.ex b/lib/mobilizon_web/resolvers/category.ex index 98a48ed11..dbc102741 100644 --- a/lib/mobilizon_web/resolvers/category.ex +++ b/lib/mobilizon_web/resolvers/category.ex @@ -2,9 +2,9 @@ defmodule MobilizonWeb.Resolvers.Category do require Logger alias Mobilizon.Actors.User - def list_categories(_parent, _args, _resolution) do + def list_categories(_parent, %{page: page, limit: limit}, _resolution) do categories = - Mobilizon.Events.list_categories() + Mobilizon.Events.list_categories(page, limit) |> Enum.map(fn category -> urls = MobilizonWeb.Uploaders.Category.urls({category.picture, category}) Map.put(category, :picture, %{url: urls.original, url_thumbnail: urls.thumb}) diff --git a/lib/mobilizon_web/resolvers/event.ex b/lib/mobilizon_web/resolvers/event.ex index df8e55f61..03a69de7e 100644 --- a/lib/mobilizon_web/resolvers/event.ex +++ b/lib/mobilizon_web/resolvers/event.ex @@ -2,8 +2,8 @@ defmodule MobilizonWeb.Resolvers.Event do alias Mobilizon.Service.ActivityPub alias Mobilizon.Actors - def list_events(_parent, _args, _resolution) do - {:ok, Mobilizon.Events.list_events()} + def list_events(_parent, %{page: page, limit: limit}, _resolution) do + {:ok, Mobilizon.Events.list_events(page, limit)} end def find_event(_parent, %{uuid: uuid}, _resolution) do @@ -26,8 +26,8 @@ defmodule MobilizonWeb.Resolvers.Event do @doc """ List participants for event (through an event request) """ - def list_participants_for_event(%{uuid: uuid}, _args, _resolution) do - {:ok, Mobilizon.Events.list_participants_for_event(uuid)} + def list_participants_for_event(%{uuid: uuid}, %{page: page, limit: limit}, _resolution) do + {:ok, Mobilizon.Events.list_participants_for_event(uuid, page, limit)} end @doc """ diff --git a/lib/mobilizon_web/resolvers/group.ex b/lib/mobilizon_web/resolvers/group.ex index a4170c7a2..9144f0861 100644 --- a/lib/mobilizon_web/resolvers/group.ex +++ b/lib/mobilizon_web/resolvers/group.ex @@ -20,8 +20,8 @@ defmodule MobilizonWeb.Resolvers.Group do @doc """ Lists all groups """ - def list_groups(_parent, _args, _resolution) do - {:ok, Actors.list_groups()} + def list_groups(_parent, %{page: page, limit: limit}, _resolution) do + {:ok, Actors.list_groups(page, limit)} end @doc """ diff --git a/lib/mobilizon_web/schema.ex b/lib/mobilizon_web/schema.ex index 4cc238f1c..cfbd783f2 100644 --- a/lib/mobilizon_web/schema.ex +++ b/lib/mobilizon_web/schema.ex @@ -322,7 +322,7 @@ defmodule MobilizonWeb.Schema do end @desc """ - Represents an actor's follower + Represents an actor's follower """ object :follower do field(:target_actor, :actor, description: "What or who the profile follows") @@ -395,11 +395,15 @@ defmodule MobilizonWeb.Schema do query do @desc "Get all events" field :events, list_of(:event) do + arg(:page, :integer, default_value: 1) + arg(:limit, :integer, default_value: 10) resolve(&Resolvers.Event.list_events/3) end @desc "Get all groups" field :groups, list_of(:group) do + arg(:page, :integer, default_value: 1) + arg(:limit, :integer, default_value: 10) resolve(&Resolvers.Group.list_groups/3) end @@ -420,6 +424,8 @@ defmodule MobilizonWeb.Schema do @desc "Get all participants for an event uuid" field :participants, list_of(:participant) do arg(:uuid, non_null(:uuid)) + arg(:page, :integer, default_value: 1) + arg(:limit, :integer, default_value: 10) resolve(&Resolvers.Event.list_participants_for_event/3) end @@ -453,6 +459,8 @@ defmodule MobilizonWeb.Schema do @desc "Get the list of categories" field :categories, non_null(list_of(:category)) do + arg(:page, :integer, default_value: 1) + arg(:limit, :integer, default_value: 10) resolve(&Resolvers.Category.list_categories/3) end end diff --git a/lib/service/activity_pub/activity_pub.ex b/lib/service/activity_pub/activity_pub.ex index ee44e1d43..22b97a1ef 100644 --- a/lib/service/activity_pub/activity_pub.ex +++ b/lib/service/activity_pub/activity_pub.ex @@ -361,7 +361,9 @@ defmodule Mobilizon.Service.ActivityPub do Return all public activities (events & comments) for an actor """ @spec fetch_public_activities_for_actor(Actor.t(), integer(), integer()) :: {list(), integer()} - def fetch_public_activities_for_actor(%Actor{} = actor, page \\ 1, limit \\ 10) do + def fetch_public_activities_for_actor(actor, page \\ nil, limit \\ nil) + + def fetch_public_activities_for_actor(%Actor{} = actor, page, limit) do case actor.type do :Person -> {:ok, events, total_events} = Events.get_events_for_actor(actor, page, limit)