Merge branch 'feature/pagination' into 'master'

Add pagination to events, groups, partipants to an event and categories

See merge request framasoft/mobilizon!26
This commit is contained in:
Thomas Citharel 2018-12-14 12:06:45 +01:00
commit ccc623bc31
11 changed files with 92 additions and 72 deletions

View file

@ -20,11 +20,13 @@ defmodule Mobilizon.Actors.Actor do
""" """
use Ecto.Schema use Ecto.Schema
import Ecto.Changeset import Ecto.Changeset
alias Mobilizon.Actors alias Mobilizon.Actors
alias Mobilizon.Actors.{Actor, User, Follower, Member} alias Mobilizon.Actors.{Actor, User, Follower, Member}
alias Mobilizon.Events.Event alias Mobilizon.Events.Event
import Ecto.Query import Ecto.Query
import Mobilizon.Ecto
alias Mobilizon.Repo alias Mobilizon.Repo
require Logger 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 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 def get_followers(%Actor{id: actor_id} = _actor, page \\ nil, limit \\ nil) do
start = (page - 1) * limit
Repo.all( Repo.all(
from( from(
a in Actor, a in Actor,
join: f in Follower, join: f in Follower,
on: a.id == f.actor_id, on: a.id == f.actor_id,
where: f.target_actor_id == ^actor_id, where: f.target_actor_id == ^actor_id
limit: ^limit,
offset: ^start
) )
|> paginate(page, limit)
) )
end 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 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 def get_followings(%Actor{id: actor_id} = _actor, page \\ nil, limit \\ nil) do
start = (page - 1) * limit
Repo.all( Repo.all(
from( from(
a in Actor, a in Actor,
join: f in Follower, join: f in Follower,
on: a.id == f.target_actor_id, on: a.id == f.target_actor_id,
where: f.actor_id == ^actor_id, where: f.actor_id == ^actor_id
limit: ^limit,
offset: ^start
) )
|> paginate(page, limit)
) )
end end

View file

@ -4,6 +4,8 @@ defmodule Mobilizon.Actors do
""" """
import Ecto.Query, warn: false import Ecto.Query, warn: false
import Mobilizon.Ecto
alias Mobilizon.Repo alias Mobilizon.Repo
alias Mobilizon.Actors.{Actor, Bot, Member, Follower, User} alias Mobilizon.Actors.{Actor, Bot, Member, Follower, User}
@ -150,8 +152,14 @@ defmodule Mobilizon.Actors do
@doc """ @doc """
List the groups List the groups
""" """
def list_groups do def list_groups(page \\ nil, limit \\ nil) do
Repo.all(from(a in Actor, where: a.type == ^:Group)) Repo.all(
from(
a in Actor,
where: a.type == ^:Group
)
|> paginate(page, limit)
)
end end
def get_group_by_name(name) do def get_group_by_name(name) do
@ -446,21 +454,18 @@ defmodule Mobilizon.Actors do
Find actors by their name or displayed name Find actors by their name or displayed name
""" """
@spec find_actors_by_username_or_name(String.t(), integer(), integer()) :: list(Actor.t()) @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("", _page, _limit), do: []
def find_actors_by_username_or_name(username, page, limit) do def find_actors_by_username_or_name(username, page, limit) do
start = (page - 1) * limit
Repo.all( Repo.all(
from( from(
a in Actor, a in Actor,
limit: ^limit,
offset: ^start,
where: where:
ilike(a.preferred_username, ^like_sanitize(username)) or ilike(a.preferred_username, ^like_sanitize(username)) or
ilike(a.name, ^like_sanitize(username)) ilike(a.name, ^like_sanitize(username))
) )
|> paginate(page, limit)
) )
end end

34
lib/mobilizon/ecto.ex Normal file
View file

@ -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

View file

@ -4,6 +4,7 @@ defmodule Mobilizon.Events do
""" """
import Ecto.Query, warn: false import Ecto.Query, warn: false
import Mobilizon.Ecto
alias Mobilizon.Repo alias Mobilizon.Repo
alias Mobilizon.Events.{Event, Comment, Participant} alias Mobilizon.Events.{Event, Comment, Participant}
@ -18,16 +19,12 @@ defmodule Mobilizon.Events do
queryable queryable
end end
def get_events_for_actor(%Actor{id: actor_id} = _actor, page \\ 1, limit \\ 10) do def get_events_for_actor(%Actor{id: actor_id} = _actor, page \\ nil, limit \\ nil) do
start = (page - 1) * limit
query = query =
from( from(
e in Event, e in Event,
where: e.organizer_actor_id == ^actor_id, where: e.organizer_actor_id == ^actor_id,
limit: ^limit,
order_by: [desc: :id], order_by: [desc: :id],
offset: ^start,
preload: [ preload: [
:organizer_actor, :organizer_actor,
:category, :category,
@ -38,6 +35,7 @@ defmodule Mobilizon.Events do
:physical_address :physical_address
] ]
) )
|> paginate(page, limit)
events = Repo.all(query) events = Repo.all(query)
@ -186,15 +184,10 @@ defmodule Mobilizon.Events do
[%Event{}, ...] [%Event{}, ...]
""" """
def list_events(page \\ 1, limit \\ 10) do def list_events(page \\ nil, limit \\ nil) do
start = (page - 1) * limit
query = query =
from(e in Event, from(e in Event, preload: [:organizer_actor])
limit: ^limit, |> paginate(page, limit)
offset: ^start,
preload: [:organizer_actor]
)
Repo.all(query) Repo.all(query)
end end
@ -202,20 +195,18 @@ defmodule Mobilizon.Events do
@doc """ @doc """
Find events by name 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("", page, limit), do: list_events(page, limit)
def find_events_by_name(name, page, limit) do def find_events_by_name(name, page, limit) do
name = String.trim(name) name = String.trim(name)
start = (page - 1) * limit
query = query =
from(e in Event, from(e in Event,
limit: ^limit,
offset: ^start,
where: ilike(e.title, ^like_sanitize(name)), where: ilike(e.title, ^like_sanitize(name)),
preload: [:organizer_actor] preload: [:organizer_actor]
) )
|> paginate(page, limit)
Repo.all(query) Repo.all(query)
end end
@ -309,8 +300,11 @@ defmodule Mobilizon.Events do
[%Category{}, ...] [%Category{}, ...]
""" """
def list_categories do def list_categories(page \\ nil, limit \\ nil) do
Repo.all(Category) Repo.all(
Category
|> paginate(page, limit)
)
end end
@doc """ @doc """
@ -519,7 +513,7 @@ defmodule Mobilizon.Events do
[%Participant{}, ...] [%Participant{}, ...]
""" """
def list_participants_for_event(uuid) do def list_participants_for_event(uuid, page \\ nil, limit \\ nil) do
Repo.all( Repo.all(
from( from(
p in Participant, p in Participant,
@ -528,6 +522,7 @@ defmodule Mobilizon.Events do
where: e.uuid == ^uuid, where: e.uuid == ^uuid,
preload: [:actor] preload: [:actor]
) )
|> paginate(page, limit)
) )
end end
@ -846,16 +841,12 @@ defmodule Mobilizon.Events do
Repo.all(Comment) Repo.all(Comment)
end end
def get_comments_for_actor(%Actor{id: actor_id}, page \\ 1, limit \\ 10) do def get_comments_for_actor(%Actor{id: actor_id}, page \\ nil, limit \\ nil) do
start = (page - 1) * limit
query = query =
from( from(
c in Comment, c in Comment,
where: c.actor_id == ^actor_id, where: c.actor_id == ^actor_id,
limit: ^limit,
order_by: [desc: :id], order_by: [desc: :id],
offset: ^start,
preload: [ preload: [
:actor, :actor,
:in_reply_to_comment, :in_reply_to_comment,
@ -863,6 +854,7 @@ defmodule Mobilizon.Events do
:event :event
] ]
) )
|> paginate(page, limit)
comments = Repo.all(query) comments = Repo.all(query)

View file

@ -25,7 +25,7 @@ defmodule Mobilizon.Events.Tag.TitleSlug do
_tag -> _tag ->
slug slug
|> Mobilizon.Slug.increment_slug() |> Mobilizon.Ecto.increment_slug()
|> build_unique_slug(changeset) |> build_unique_slug(changeset)
end end
end end

View file

@ -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

View file

@ -2,9 +2,9 @@ defmodule MobilizonWeb.Resolvers.Category do
require Logger require Logger
alias Mobilizon.Actors.User alias Mobilizon.Actors.User
def list_categories(_parent, _args, _resolution) do def list_categories(_parent, %{page: page, limit: limit}, _resolution) do
categories = categories =
Mobilizon.Events.list_categories() Mobilizon.Events.list_categories(page, limit)
|> Enum.map(fn category -> |> Enum.map(fn category ->
urls = MobilizonWeb.Uploaders.Category.urls({category.picture, category}) urls = MobilizonWeb.Uploaders.Category.urls({category.picture, category})
Map.put(category, :picture, %{url: urls.original, url_thumbnail: urls.thumb}) Map.put(category, :picture, %{url: urls.original, url_thumbnail: urls.thumb})

View file

@ -2,8 +2,8 @@ defmodule MobilizonWeb.Resolvers.Event do
alias Mobilizon.Service.ActivityPub alias Mobilizon.Service.ActivityPub
alias Mobilizon.Actors alias Mobilizon.Actors
def list_events(_parent, _args, _resolution) do def list_events(_parent, %{page: page, limit: limit}, _resolution) do
{:ok, Mobilizon.Events.list_events()} {:ok, Mobilizon.Events.list_events(page, limit)}
end end
def find_event(_parent, %{uuid: uuid}, _resolution) do def find_event(_parent, %{uuid: uuid}, _resolution) do
@ -26,8 +26,8 @@ defmodule MobilizonWeb.Resolvers.Event do
@doc """ @doc """
List participants for event (through an event request) List participants for event (through an event request)
""" """
def list_participants_for_event(%{uuid: uuid}, _args, _resolution) do def list_participants_for_event(%{uuid: uuid}, %{page: page, limit: limit}, _resolution) do
{:ok, Mobilizon.Events.list_participants_for_event(uuid)} {:ok, Mobilizon.Events.list_participants_for_event(uuid, page, limit)}
end end
@doc """ @doc """

View file

@ -20,8 +20,8 @@ defmodule MobilizonWeb.Resolvers.Group do
@doc """ @doc """
Lists all groups Lists all groups
""" """
def list_groups(_parent, _args, _resolution) do def list_groups(_parent, %{page: page, limit: limit}, _resolution) do
{:ok, Actors.list_groups()} {:ok, Actors.list_groups(page, limit)}
end end
@doc """ @doc """

View file

@ -322,7 +322,7 @@ defmodule MobilizonWeb.Schema do
end end
@desc """ @desc """
Represents an actor's follower Represents an actor's follower
""" """
object :follower do object :follower do
field(:target_actor, :actor, description: "What or who the profile follows") field(:target_actor, :actor, description: "What or who the profile follows")
@ -395,11 +395,15 @@ defmodule MobilizonWeb.Schema do
query do query do
@desc "Get all events" @desc "Get all events"
field :events, list_of(:event) do field :events, list_of(:event) do
arg(:page, :integer, default_value: 1)
arg(:limit, :integer, default_value: 10)
resolve(&Resolvers.Event.list_events/3) resolve(&Resolvers.Event.list_events/3)
end end
@desc "Get all groups" @desc "Get all groups"
field :groups, list_of(:group) do field :groups, list_of(:group) do
arg(:page, :integer, default_value: 1)
arg(:limit, :integer, default_value: 10)
resolve(&Resolvers.Group.list_groups/3) resolve(&Resolvers.Group.list_groups/3)
end end
@ -420,6 +424,8 @@ defmodule MobilizonWeb.Schema do
@desc "Get all participants for an event uuid" @desc "Get all participants for an event uuid"
field :participants, list_of(:participant) do field :participants, list_of(:participant) do
arg(:uuid, non_null(:uuid)) 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) resolve(&Resolvers.Event.list_participants_for_event/3)
end end
@ -453,6 +459,8 @@ defmodule MobilizonWeb.Schema do
@desc "Get the list of categories" @desc "Get the list of categories"
field :categories, non_null(list_of(:category)) do 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) resolve(&Resolvers.Category.list_categories/3)
end end
end end

View file

@ -361,7 +361,9 @@ defmodule Mobilizon.Service.ActivityPub do
Return all public activities (events & comments) for an actor Return all public activities (events & comments) for an actor
""" """
@spec fetch_public_activities_for_actor(Actor.t(), integer(), integer()) :: {list(), integer()} @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 case actor.type do
:Person -> :Person ->
{:ok, events, total_events} = Events.get_events_for_actor(actor, page, limit) {:ok, events, total_events} = Events.get_events_for_actor(actor, page, limit)