Introduce new ingestion pipeline structure, implement internal Likes with it.
This commit is contained in:
parent
e3b4a3e96b
commit
6e4f52f8a2
22 changed files with 284 additions and 47 deletions
|
|
@ -18,6 +18,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
alias Pleroma.Web.ActivityPub.MRF
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
alias Pleroma.Web.ActivityPub.ObjectValidator
|
||||
alias Pleroma.Web.ActivityPub.SideEffects
|
||||
alias Pleroma.Web.Streamer
|
||||
alias Pleroma.Web.WebFinger
|
||||
alias Pleroma.Workers.BackgroundWorker
|
||||
|
|
@ -123,6 +125,38 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|
||||
def increase_poll_votes_if_vote(_create_data), do: :noop
|
||||
|
||||
@spec common_pipeline(map(), keyword()) :: {:ok, Activity.t(), keyword()} | {:error, any()}
|
||||
def common_pipeline(object, meta) do
|
||||
with {_, {:ok, validated_object, meta}} <-
|
||||
{:validate_object, ObjectValidator.validate(object, meta)},
|
||||
{_, {:ok, mrfd_object}} <- {:mrf_object, MRF.filter(validated_object)},
|
||||
{_, {:ok, %Activity{} = activity, meta}} <-
|
||||
{:persist_object, persist(mrfd_object, meta)},
|
||||
{_, {:ok, %Activity{} = activity, meta}} <-
|
||||
{:execute_side_effects, SideEffects.handle(activity, meta)} do
|
||||
{:ok, activity, meta}
|
||||
else
|
||||
e -> {:error, e}
|
||||
end
|
||||
end
|
||||
|
||||
# TODO rewrite in with style
|
||||
@spec persist(map(), keyword()) :: {:ok, Activity.t() | Object.t()}
|
||||
def persist(object, meta) do
|
||||
local = Keyword.get(meta, :local)
|
||||
{recipients, _, _} = get_recipients(object)
|
||||
|
||||
{:ok, activity} =
|
||||
Repo.insert(%Activity{
|
||||
data: object,
|
||||
local: local,
|
||||
recipients: recipients,
|
||||
actor: object["actor"]
|
||||
})
|
||||
|
||||
{:ok, activity, meta}
|
||||
end
|
||||
|
||||
def insert(map, local \\ true, fake \\ false, bypass_actor_check \\ false) when is_map(map) do
|
||||
with nil <- Activity.normalize(map),
|
||||
map <- lazy_put_activity_defaults(map, fake),
|
||||
|
|
@ -130,6 +164,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
{_, true} <- {:remote_limit_error, check_remote_limit(map)},
|
||||
{:ok, map} <- MRF.filter(map),
|
||||
{recipients, _, _} = get_recipients(map),
|
||||
# ???
|
||||
{:fake, false, map, recipients} <- {:fake, fake, map, recipients},
|
||||
:ok <- Containment.contain_child(map),
|
||||
{:ok, map, object} <- insert_full_object(map) do
|
||||
|
|
|
|||
43
lib/pleroma/web/activity_pub/builder.ex
Normal file
43
lib/pleroma/web/activity_pub/builder.ex
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
defmodule Pleroma.Web.ActivityPub.Builder do
|
||||
@moduledoc """
|
||||
This module builds the objects. Meant to be used for creating local objects.
|
||||
|
||||
This module encodes our addressing policies and general shape of our objects.
|
||||
"""
|
||||
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
alias Pleroma.Web.ActivityPub.Visibility
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Object
|
||||
|
||||
@spec like(User.t(), Object.t()) :: {:ok, map(), keyword()}
|
||||
def like(actor, object) do
|
||||
object_actor = User.get_cached_by_ap_id(object.data["actor"])
|
||||
|
||||
# Address the actor of the object, and our actor's follower collection if the post is public.
|
||||
to =
|
||||
if Visibility.is_public?(object) do
|
||||
[actor.follower_address, object.data["actor"]]
|
||||
else
|
||||
[object.data["actor"]]
|
||||
end
|
||||
|
||||
# CC everyone who's been addressed in the object, except ourself and the object actor's
|
||||
# follower collection
|
||||
cc =
|
||||
(object.data["to"] ++ (object.data["cc"] || []))
|
||||
|> List.delete(actor.ap_id)
|
||||
|> List.delete(object_actor.follower_address)
|
||||
|
||||
{:ok,
|
||||
%{
|
||||
"id" => Utils.generate_activity_id(),
|
||||
"actor" => actor.ap_id,
|
||||
"type" => "Like",
|
||||
"object" => object.data["id"],
|
||||
"to" => to,
|
||||
"cc" => cc,
|
||||
"context" => object.data["context"]
|
||||
}, []}
|
||||
end
|
||||
end
|
||||
57
lib/pleroma/web/activity_pub/object_validator.ex
Normal file
57
lib/pleroma/web/activity_pub/object_validator.ex
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
||||
@moduledoc """
|
||||
This module is responsible for validating an object (which can be an activity)
|
||||
and checking if it is both well formed and also compatible with our view of
|
||||
the system.
|
||||
"""
|
||||
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
|
||||
def validate_id(object, meta) do
|
||||
with {_, true} <- {:id_presence, Map.has_key?(object, "id")} do
|
||||
{:ok, object, meta}
|
||||
else
|
||||
e -> {:error, e}
|
||||
end
|
||||
end
|
||||
|
||||
def validate_actor(object, meta) do
|
||||
with {_, %User{}} <- {:actor_validation, User.get_cached_by_ap_id(object["actor"])} do
|
||||
{:ok, object, meta}
|
||||
else
|
||||
e -> {:error, e}
|
||||
end
|
||||
end
|
||||
|
||||
def common_validations(object, meta) do
|
||||
with {_, {:ok, object, meta}} <- {:validate_id, validate_id(object, meta)},
|
||||
{_, {:ok, object, meta}} <- {:validate_actor, validate_actor(object, meta)} do
|
||||
{:ok, object, meta}
|
||||
else
|
||||
e -> {:error, e}
|
||||
end
|
||||
end
|
||||
|
||||
@spec validate(map(), keyword()) :: {:ok, map(), keyword()} | {:error, any()}
|
||||
def validate(object, meta)
|
||||
|
||||
def validate(%{"type" => "Like"} = object, meta) do
|
||||
with {:ok, object, meta} <- common_validations(object, meta),
|
||||
{_, %Object{} = liked_object} <- {:find_liked_object, Object.normalize(object["object"])},
|
||||
{_, nil} <- {:existing_like, Utils.get_existing_like(object["actor"], liked_object)} do
|
||||
{:ok, object, meta}
|
||||
else
|
||||
e -> {:error, e}
|
||||
end
|
||||
end
|
||||
|
||||
def validate(object, meta) do
|
||||
common_validations(object, meta)
|
||||
end
|
||||
end
|
||||
28
lib/pleroma/web/activity_pub/side_effects.ex
Normal file
28
lib/pleroma/web/activity_pub/side_effects.ex
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
defmodule Pleroma.Web.ActivityPub.SideEffects do
|
||||
@moduledoc """
|
||||
This module looks at an inserted object and executes the side effects that it
|
||||
implies. For example, a `Like` activity will increase the like count on the
|
||||
liked object, a `Follow` activity will add the user to the follower
|
||||
collection, and so on.
|
||||
"""
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Notification
|
||||
|
||||
def handle(object, meta \\ [])
|
||||
|
||||
# Tasks this handles:
|
||||
# - Add like to object
|
||||
# - Set up notification
|
||||
def handle(%{data: %{"type" => "Like"}} = object, meta) do
|
||||
liked_object = Object.get_by_ap_id(object.data["object"])
|
||||
Utils.add_like_to_object(object, liked_object)
|
||||
Notification.create_notifications(object)
|
||||
{:ok, object, meta}
|
||||
end
|
||||
|
||||
# Nothing to do
|
||||
def handle(object, meta) do
|
||||
{:ok, object, meta}
|
||||
end
|
||||
end
|
||||
|
|
@ -10,6 +10,7 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
alias Pleroma.ThreadMute
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.ActivityPub.Builder
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
alias Pleroma.Web.ActivityPub.Visibility
|
||||
|
||||
|
|
@ -17,6 +18,7 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
import Pleroma.Web.CommonAPI.Utils
|
||||
|
||||
require Pleroma.Constants
|
||||
require Logger
|
||||
|
||||
def follow(follower, followed) do
|
||||
timeout = Pleroma.Config.get([:activitypub, :follow_handshake_timeout])
|
||||
|
|
@ -98,16 +100,31 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
end
|
||||
end
|
||||
|
||||
def favorite(id_or_ap_id, user) do
|
||||
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
|
||||
object <- Object.normalize(activity),
|
||||
nil <- Utils.get_existing_like(user.ap_id, object) do
|
||||
ActivityPub.like(user, object)
|
||||
@spec favorite(User.t(), binary()) :: {:ok, Activity.t()} | {:error, any()}
|
||||
def favorite(%User{} = user, id) do
|
||||
with {_, %Activity{object: object}} <- {:find_object, Activity.get_by_id_with_object(id)},
|
||||
{_, {:ok, like_object, meta}} <- {:build_object, Builder.like(user, object)},
|
||||
{_, {:ok, %Activity{} = activity, _meta}} <-
|
||||
{:common_pipeline,
|
||||
ActivityPub.common_pipeline(like_object, Keyword.put(meta, :local, true))} do
|
||||
{:ok, activity}
|
||||
else
|
||||
_ -> {:error, dgettext("errors", "Could not favorite")}
|
||||
e ->
|
||||
Logger.error("Could not favorite #{id}. Error: #{inspect(e, pretty: true)}")
|
||||
{:error, dgettext("errors", "Could not favorite")}
|
||||
end
|
||||
end
|
||||
|
||||
# def favorite(id_or_ap_id, user) do
|
||||
# with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
|
||||
# object <- Object.normalize(activity),
|
||||
# nil <- Utils.get_existing_like(user.ap_id, object) do
|
||||
# ActivityPub.like(user, object)
|
||||
# else
|
||||
# _ -> {:error, dgettext("errors", "Could not favorite")}
|
||||
# end
|
||||
# end
|
||||
|
||||
def unfavorite(id_or_ap_id, user) do
|
||||
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id) do
|
||||
object = Object.normalize(activity)
|
||||
|
|
|
|||
|
|
@ -201,9 +201,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
|
|||
end
|
||||
|
||||
@doc "POST /api/v1/statuses/:id/favourite"
|
||||
def favourite(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
|
||||
with {:ok, _fav, %{data: %{"id" => id}}} <- CommonAPI.favorite(ap_id_or_id, user),
|
||||
%Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
|
||||
def favourite(%{assigns: %{user: user}} = conn, %{"id" => activity_id}) do
|
||||
with {:ok, _fav} <- CommonAPI.favorite(user, activity_id),
|
||||
%Activity{} = activity <- Activity.get_by_id(activity_id) do
|
||||
try_render(conn, "show.json", activity: activity, for: user, as: :activity)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue