defmodule Mobilizon.FollowedGroupActivity do @moduledoc """ Provide recent elements from groups that profiles follow """ import Ecto.Query alias Mobilizon.Actors.{Actor, Follower, Member} alias Mobilizon.Events.{Event, Participant} alias Mobilizon.Storage.Page @spec user_followed_group_events( integer() | String.t(), DateTime.t() | nil, integer() | nil, integer() | nil ) :: Page.t(Event.t()) def user_followed_group_events(user_id, after_datetime \\ nil, page \\ nil, limit \\ nil) do Event |> distinct([e], [e.begins_on, e.id]) |> join(:left, [e], p in Participant, on: e.id == p.event_id) |> join(:inner, [_e, p], pa in Actor, on: p.actor_id == pa.id) |> join(:inner, [e], g in Actor, on: e.attributed_to_id == g.id) |> join(:left, [_e, _p, _pa, g], f in Follower, on: g.id == f.target_actor_id) |> join(:left, [_e, _p, _pa, g], m in Member, on: g.id == m.parent_id) |> join(:inner, [_e, _p, pa, _g, f, m], a in Actor, on: a.id == f.actor_id or a.id == m.actor_id ) |> add_after_datetime_filter(after_datetime) |> where( [_e, p, pa, _g, f, m, a], (f.approved or m.role in ^[:member, :moderator, :administrator, :creator]) and a.user_id == ^user_id and pa.user_id != ^user_id ) |> preload([ :organizer_actor, :attributed_to, :tags, :physical_address, :picture ]) |> select([e, g, _f, _m, a], [ e, g, a ]) |> Page.build_page(page, limit) end @spec add_after_datetime_filter(Ecto.Query.t(), DateTime.t() | nil) :: Ecto.Query.t() defp add_after_datetime_filter(query, nil), do: where(query, [e], e.begins_on > ^DateTime.utc_now()) defp add_after_datetime_filter(query, %DateTime{} = datetime), do: where(query, [e], e.begins_on > ^datetime) end