# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ActivityPub do
require Pleroma.Constants
@behaviour Pleroma.Web.ActivityPub.ActivityPub.Persisting
+ @behaviour Pleroma.Web.ActivityPub.ActivityPub.Streaming
defp get_recipients(%{"type" => "Create"} = data) do
to = Map.get(data, "to", [])
defp check_actor_is_active(actor) when is_binary(actor) do
case User.get_cached_by_ap_id(actor) do
- %User{deactivated: deactivated} -> not deactivated
+ %User{is_active: true} -> true
_ -> false
end
end
Streamer.stream("participation", participations)
end
+ @impl true
def stream_out_participations(%Object{data: %{"context" => context}}, user) do
with %Conversation{} = conversation <- Conversation.get_for_ap_id(context) do
conversation = Repo.preload(conversation, :participations)
end
end
+ @impl true
def stream_out_participations(_, _), do: :noop
+ @impl true
def stream_out(%Activity{data: %{"type" => data_type}} = activity)
when data_type in ["Create", "Announce", "Delete"] do
activity
|> Streamer.stream(activity)
end
+ @impl true
def stream_out(_activity) do
:noop
end
|> Map.put(:muting_user, reading_user)
end
+ pagination_type = Map.get(params, :pagination_type) || :keyset
+
%{
godmode: params[:godmode],
reading_user: reading_user
}
|> user_activities_recipients()
- |> fetch_activities(params)
+ |> fetch_activities(params, pagination_type)
|> Enum.reverse()
end
defp restrict_since(query, _), do: query
- defp restrict_tag_reject(_query, %{tag_reject: _tag_reject, skip_preload: true}) do
- raise_on_missing_preload()
- end
-
- defp restrict_tag_reject(query, %{tag_reject: tag_reject}) when is_list(tag_reject) do
- from(
- [_activity, object] in query,
- where: fragment("not (?)->'tag' \\?| (?)", object.data, ^tag_reject)
- )
- end
-
- defp restrict_tag_reject(query, %{tag_reject: tag_reject}) when is_binary(tag_reject) do
- restrict_tag_reject(query, %{tag_reject: [tag_reject]})
- end
-
- defp restrict_tag_reject(query, _), do: query
-
- defp restrict_tag_all(_query, %{tag_all: _tag_all, skip_preload: true}) do
+ defp restrict_embedded_tag_all(_query, %{tag_all: _tag_all, skip_preload: true}) do
raise_on_missing_preload()
end
- defp restrict_tag_all(query, %{tag_all: tag_all}) when is_list(tag_all) do
+ defp restrict_embedded_tag_all(query, %{tag_all: tag_all}) when is_list(tag_all) do
from(
[_activity, object] in query,
where: fragment("(?)->'tag' \\?& (?)", object.data, ^tag_all)
)
end
- defp restrict_tag_all(query, %{tag_all: tag}) when is_binary(tag) do
- restrict_tag(query, %{tag: tag})
+ defp restrict_embedded_tag_all(query, %{tag_all: tag}) when is_binary(tag) do
+ restrict_embedded_tag_any(query, %{tag: tag})
end
- defp restrict_tag_all(query, _), do: query
+ defp restrict_embedded_tag_all(query, _), do: query
- defp restrict_tag(_query, %{tag: _tag, skip_preload: true}) do
+ defp restrict_embedded_tag_any(_query, %{tag: _tag, skip_preload: true}) do
raise_on_missing_preload()
end
- defp restrict_tag(query, %{tag: tag}) when is_list(tag) do
+ defp restrict_embedded_tag_any(query, %{tag: tag}) when is_list(tag) do
from(
[_activity, object] in query,
where: fragment("(?)->'tag' \\?| (?)", object.data, ^tag)
)
end
- defp restrict_tag(query, %{tag: tag}) when is_binary(tag) do
- restrict_tag(query, %{tag: [tag]})
+ defp restrict_embedded_tag_any(query, %{tag: tag}) when is_binary(tag) do
+ restrict_embedded_tag_any(query, %{tag: [tag]})
end
- defp restrict_tag(query, _), do: query
+ defp restrict_embedded_tag_any(query, _), do: query
- defp restrict_hashtag_reject_any(_query, %{tag_reject: _tag_reject, skip_preload: true}) do
+ defp restrict_embedded_tag_reject_any(_query, %{tag_reject: _tag_reject, skip_preload: true}) do
raise_on_missing_preload()
end
- defp restrict_hashtag_reject_any(query, %{tag_reject: tags_reject}) when is_list(tags_reject) do
- if has_named_binding?(query, :thread_mute) do
- from(
- [activity, object, thread_mute] in query,
- group_by: [activity.id, object.id, thread_mute.id]
- )
- else
- from(
- [activity, object] in query,
- group_by: [activity.id, object.id]
- )
- end
- |> join(:left, [_activity, object], hashtag in assoc(object, :hashtags), as: :hashtag)
- |> having(
- [hashtag: hashtag],
- fragment("not(array_agg(?) && (?))", hashtag.name, ^tags_reject)
+ defp restrict_embedded_tag_reject_any(query, %{tag_reject: tag_reject})
+ when is_list(tag_reject) do
+ from(
+ [_activity, object] in query,
+ where: fragment("not (?)->'tag' \\?| (?)", object.data, ^tag_reject)
)
end
- defp restrict_hashtag_reject_any(query, %{tag_reject: tag_reject}) when is_binary(tag_reject) do
- restrict_hashtag_reject_any(query, %{tag_reject: [tag_reject]})
+ defp restrict_embedded_tag_reject_any(query, %{tag_reject: tag_reject})
+ when is_binary(tag_reject) do
+ restrict_embedded_tag_reject_any(query, %{tag_reject: [tag_reject]})
end
- defp restrict_hashtag_reject_any(query, _), do: query
+ defp restrict_embedded_tag_reject_any(query, _), do: query
defp restrict_hashtag_all(_query, %{tag_all: _tag, skip_preload: true}) do
raise_on_missing_preload()
end
defp restrict_hashtag_all(query, %{tag_all: tags}) when is_list(tags) do
- Enum.reduce(
- tags,
- query,
- fn tag, acc -> restrict_hashtag_any(acc, %{tag: tag}) end
+ from(
+ [_activity, object] in query,
+ where:
+ fragment(
+ """
+ (SELECT array_agg(hashtags.name) FROM hashtags JOIN hashtags_objects
+ ON hashtags_objects.hashtag_id = hashtags.id WHERE hashtags.name = ANY(?)
+ AND hashtags_objects.object_id = ?) @> ?
+ """,
+ ^tags,
+ object.id,
+ ^tags
+ )
)
end
defp restrict_hashtag_any(query, %{tag: tags}) when is_list(tags) do
from(
[_activity, object] in query,
- join: hashtag in assoc(object, :hashtags),
- where: hashtag.name in ^tags
+ where:
+ fragment(
+ """
+ EXISTS (SELECT 1 FROM hashtags JOIN hashtags_objects
+ ON hashtags_objects.hashtag_id = hashtags.id WHERE hashtags.name = ANY(?)
+ AND hashtags_objects.object_id = ? LIMIT 1)
+ """,
+ ^tags,
+ object.id
+ )
)
end
defp restrict_hashtag_any(query, _), do: query
+ defp restrict_hashtag_reject_any(_query, %{tag_reject: _tag_reject, skip_preload: true}) do
+ raise_on_missing_preload()
+ end
+
+ defp restrict_hashtag_reject_any(query, %{tag_reject: tags_reject}) when is_list(tags_reject) do
+ from(
+ [_activity, object] in query,
+ where:
+ fragment(
+ """
+ NOT EXISTS (SELECT 1 FROM hashtags JOIN hashtags_objects
+ ON hashtags_objects.hashtag_id = hashtags.id WHERE hashtags.name = ANY(?)
+ AND hashtags_objects.object_id = ? LIMIT 1)
+ """,
+ ^tags_reject,
+ object.id
+ )
+ )
+ end
+
+ defp restrict_hashtag_reject_any(query, %{tag_reject: tag_reject}) when is_binary(tag_reject) do
+ restrict_hashtag_reject_any(query, %{tag_reject: [tag_reject]})
+ end
+
+ defp restrict_hashtag_reject_any(query, _), do: query
+
defp raise_on_missing_preload do
raise "Can't use the child object without preloading!"
end
query =
Activity
- |> distinct([a], true)
|> maybe_preload_objects(opts)
|> maybe_preload_bookmarks(opts)
|> maybe_preload_report_notes(opts)
|> exclude_invisible_actors(opts)
|> exclude_visibility(opts)
- if Config.object_embedded_hashtags?() do
- query
- |> restrict_tag(opts)
- |> restrict_tag_reject(opts)
- |> restrict_tag_all(opts)
- else
+ if Config.improved_hashtag_timeline() do
query
|> restrict_hashtag_any(opts)
|> restrict_hashtag_all(opts)
|> restrict_hashtag_reject_any(opts)
+ else
+ query
+ |> restrict_embedded_tag_any(opts)
+ |> restrict_embedded_tag_all(opts)
+ |> restrict_embedded_tag_reject_any(opts)
end
end