A module to handle coding from internal to wire ActivityPub and back.
"""
alias Pleroma.Activity
+ alias Pleroma.FollowingRelationship
alias Pleroma.Object
alias Pleroma.Object.Containment
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.ActivityPub.ObjectValidator
+ alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
+ alias Pleroma.Web.ActivityPub.Pipeline
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.Federator
{_, false} <- {:user_locked, User.locked?(followed)},
{_, {:ok, follower}} <- {:follow, User.follow(follower, followed)},
{_, {:ok, _}} <-
- {:follow_state_update, Utils.update_follow_state_for_all(activity, "accept")} do
+ {:follow_state_update, Utils.update_follow_state_for_all(activity, "accept")},
+ {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "accept") do
ActivityPub.accept(%{
to: [follower.ap_id],
actor: followed,
else
{:user_blocked, true} ->
{:ok, _} = Utils.update_follow_state_for_all(activity, "reject")
+ {:ok, _relationship} = FollowingRelationship.update(follower, followed, "reject")
ActivityPub.reject(%{
to: [follower.ap_id],
{:follow, {:error, _}} ->
{:ok, _} = Utils.update_follow_state_for_all(activity, "reject")
+ {:ok, _relationship} = FollowingRelationship.update(follower, followed, "reject")
ActivityPub.reject(%{
to: [follower.ap_id],
})
{:user_locked, true} ->
+ {:ok, _relationship} = FollowingRelationship.update(follower, followed, "pending")
:noop
end
{:ok, follow_activity} <- get_follow_activity(follow_object, followed),
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "accept"),
%User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
- {:ok, _follower} = User.follow(follower, followed) do
+ {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "accept") do
ActivityPub.accept(%{
to: follow_activity.data["to"],
type: "Accept",
{:ok, follow_activity} <- get_follow_activity(follow_object, followed),
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "reject"),
%User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
+ {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "reject"),
{:ok, activity} <-
ActivityPub.reject(%{
to: follow_activity.data["to"],
local: false,
activity_id: id
}) do
- User.unfollow(follower, followed)
-
{:ok, activity}
else
_e -> :error
end
end
- def handle_incoming(
- %{"type" => "Like", "object" => object_id, "actor" => _actor, "id" => id} = data,
- _options
- ) do
- with actor <- Containment.get_actor(data),
- {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor),
- {:ok, object} <- get_obj_helper(object_id),
- {:ok, activity, _object} <- ActivityPub.like(actor, object, id, false) do
+ def handle_incoming(%{"type" => "Like"} = data, _options) do
+ with {_, {:ok, cast_data_sym}} <-
+ {:casting_data,
+ data |> LikeValidator.cast_data() |> Ecto.Changeset.apply_action(:insert)},
+ {_, cast_data} <-
+ {:stringify_keys, ObjectValidator.stringify_keys(cast_data_sym |> Map.from_struct())},
+ :ok <- ObjectValidator.fetch_actor_and_object(cast_data),
+ {_, {:ok, cast_data}} <- {:maybe_add_context, maybe_add_context_from_object(cast_data)},
+ {_, {:ok, cast_data}} <-
+ {:maybe_add_recipients, maybe_add_recipients_from_object(cast_data)},
+ {_, {:ok, activity, _meta}} <-
+ {:common_pipeline, Pipeline.common_pipeline(cast_data, local: false)} do
{:ok, activity}
else
- _e -> :error
+ e -> {:error, e}
end
end
# we pass a fake user so that the followers collection is stripped away
old_follower_address = User.ap_followers(%User{nickname: user.nickname})
- q =
- from(
- u in User,
- where: ^old_follower_address in u.following,
- update: [
- set: [
- following:
- fragment(
- "array_replace(?,?,?)",
- u.following,
- ^old_follower_address,
- ^user.follower_address
- )
- ]
+ from(
+ a in Activity,
+ where: ^old_follower_address in a.recipients,
+ update: [
+ set: [
+ recipients:
+ fragment(
+ "array_replace(?,?,?)",
+ a.recipients,
+ ^old_follower_address,
+ ^user.follower_address
+ )
]
- )
-
- Repo.update_all(q, [])
-
- q =
- from(
- a in Activity,
- where: ^old_follower_address in a.recipients,
- update: [
- set: [
- recipients:
- fragment(
- "array_replace(?,?,?)",
- a.recipients,
- ^old_follower_address,
- ^user.follower_address
- )
- ]
- ]
- )
-
- Repo.update_all(q, [])
+ ]
+ )
+ |> Repo.update_all([])
end
def upgrade_user_from_ap_id(ap_id) do
def maybe_fix_user_url(data), do: data
def maybe_fix_user_object(data), do: maybe_fix_user_url(data)
+
+ defp maybe_add_context_from_object(%{"context" => context} = data) when is_binary(context),
+ do: {:ok, data}
+
+ defp maybe_add_context_from_object(%{"object" => object} = data) when is_binary(object) do
+ if object = Object.normalize(object) do
+ data =
+ data
+ |> Map.put("context", object.data["context"])
+
+ {:ok, data}
+ else
+ {:error, "No context on referenced object"}
+ end
+ end
+
+ defp maybe_add_context_from_object(_) do
+ {:error, "No referenced object"}
+ end
+
+ defp maybe_add_recipients_from_object(%{"object" => object} = data) do
+ to = data["to"] || []
+ cc = data["cc"] || []
+
+ if to == [] && cc == [] do
+ if object = Object.normalize(object) do
+ data =
+ data
+ |> Map.put("to", [object.data["actor"]])
+ |> Map.put("cc", cc)
+
+ {:ok, data}
+ else
+ {:error, "No actor on referenced object"}
+ end
+ else
+ {:ok, data}
+ end
+ end
+
+ defp maybe_add_recipients_from_object(_) do
+ {:error, "No referenced object"}
+ end
end