SideEffects: port ones from ActivityPub.do_create and ActivityPub.insert
This commit is contained in:
parent
4f70fd4105
commit
82895a4012
|
@ -55,7 +55,7 @@ defp compare_uris(%URI{host: host} = _id_uri, %URI{host: host} = _other_uri), do
|
||||||
defp compare_uris(_id_uri, _other_uri), do: :error
|
defp compare_uris(_id_uri, _other_uri), do: :error
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Checks that an imported AP object's actor matches the domain it came from.
|
Checks that an imported AP object's actor matches the host it came from.
|
||||||
"""
|
"""
|
||||||
def contain_origin(_id, %{"actor" => nil}), do: :error
|
def contain_origin(_id, %{"actor" => nil}), do: :error
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ defp check_remote_limit(%{"object" => %{"content" => content}}) when not is_nil(
|
||||||
|
|
||||||
defp check_remote_limit(_), do: true
|
defp check_remote_limit(_), do: true
|
||||||
|
|
||||||
defp increase_note_count_if_public(actor, object) do
|
def increase_note_count_if_public(actor, object) do
|
||||||
if is_public?(object), do: User.increase_note_count(actor), else: {:ok, actor}
|
if is_public?(object), do: User.increase_note_count(actor), else: {:ok, actor}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -85,16 +85,6 @@ defp increase_replies_count_if_reply(%{
|
||||||
|
|
||||||
defp increase_replies_count_if_reply(_create_data), do: :noop
|
defp increase_replies_count_if_reply(_create_data), do: :noop
|
||||||
|
|
||||||
defp increase_poll_votes_if_vote(%{
|
|
||||||
"object" => %{"inReplyTo" => reply_ap_id, "name" => name},
|
|
||||||
"type" => "Create",
|
|
||||||
"actor" => actor
|
|
||||||
}) do
|
|
||||||
Object.increase_vote_count(reply_ap_id, name, actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp increase_poll_votes_if_vote(_create_data), do: :noop
|
|
||||||
|
|
||||||
@object_types ["ChatMessage", "Question", "Answer"]
|
@object_types ["ChatMessage", "Question", "Answer"]
|
||||||
@spec persist(map(), keyword()) :: {:ok, Activity.t() | Object.t()}
|
@spec persist(map(), keyword()) :: {:ok, Activity.t() | Object.t()}
|
||||||
def persist(%{"type" => type} = object, meta) when type in @object_types do
|
def persist(%{"type" => type} = object, meta) when type in @object_types do
|
||||||
|
@ -258,7 +248,6 @@ defp do_create(%{to: to, actor: actor, context: context, object: object} = param
|
||||||
with {:ok, activity} <- insert(create_data, local, fake),
|
with {:ok, activity} <- insert(create_data, local, fake),
|
||||||
{:fake, false, activity} <- {:fake, fake, activity},
|
{:fake, false, activity} <- {:fake, fake, activity},
|
||||||
_ <- increase_replies_count_if_reply(create_data),
|
_ <- increase_replies_count_if_reply(create_data),
|
||||||
_ <- increase_poll_votes_if_vote(create_data),
|
|
||||||
{:quick_insert, false, activity} <- {:quick_insert, quick_insert?, activity},
|
{:quick_insert, false, activity} <- {:quick_insert, quick_insert?, activity},
|
||||||
{:ok, _actor} <- increase_note_count_if_public(actor, activity),
|
{:ok, _actor} <- increase_note_count_if_public(actor, activity),
|
||||||
_ <- notify_and_stream(activity),
|
_ <- notify_and_stream(activity),
|
||||||
|
|
|
@ -115,6 +115,21 @@ def chat_message(actor, recipient, content, opts \\ []) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def answer(user, object, name) do
|
||||||
|
{:ok,
|
||||||
|
%{
|
||||||
|
"type" => "Answer",
|
||||||
|
"actor" => user.ap_id,
|
||||||
|
"cc" => [object.data["actor"]],
|
||||||
|
"to" => [],
|
||||||
|
"name" => name,
|
||||||
|
"inReplyTo" => object.data["id"],
|
||||||
|
"context" => object.data["context"],
|
||||||
|
"published" => DateTime.utc_now() |> DateTime.to_iso8601(),
|
||||||
|
"id" => Utils.generate_object_id()
|
||||||
|
}, []}
|
||||||
|
end
|
||||||
|
|
||||||
@spec tombstone(String.t(), String.t()) :: {:ok, map(), keyword()}
|
@spec tombstone(String.t(), String.t()) :: {:ok, map(), keyword()}
|
||||||
def tombstone(actor, id) do
|
def tombstone(actor, id) do
|
||||||
{:ok,
|
{:ok,
|
||||||
|
|
|
@ -17,7 +17,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CreateChatMessageValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CreateChatMessageValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CreateQuestionValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.FollowValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.FollowValidator
|
||||||
|
@ -162,7 +162,7 @@ def validate(
|
||||||
meta = Keyword.put(meta, :object_data, object_data |> stringify_keys),
|
meta = Keyword.put(meta, :object_data, object_data |> stringify_keys),
|
||||||
{:ok, create_activity} <-
|
{:ok, create_activity} <-
|
||||||
create_activity
|
create_activity
|
||||||
|> CreateQuestionValidator.cast_and_validate(meta)
|
|> CreateGenericValidator.cast_and_validate(meta)
|
||||||
|> Ecto.Changeset.apply_action(:insert) do
|
|> Ecto.Changeset.apply_action(:insert) do
|
||||||
create_activity = stringify_keys(create_activity)
|
create_activity = stringify_keys(create_activity)
|
||||||
{:ok, create_activity, meta}
|
{:ok, create_activity, meta}
|
||||||
|
@ -188,7 +188,7 @@ def cast_and_apply(%{"type" => "Question"} = object) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_and_apply(%{"type" => "Answer"} = object) do
|
def cast_and_apply(%{"type" => "Answer"} = object) do
|
||||||
QuestionValidator.cast_and_apply(object)
|
AnswerValidator.cast_and_apply(object)
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_and_apply(o), do: {:error, {:validator_not_set, o}}
|
def cast_and_apply(o), do: {:error, {:validator_not_set, o}}
|
||||||
|
|
|
@ -13,22 +13,25 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnswerValidator do
|
||||||
@primary_key false
|
@primary_key false
|
||||||
@derive Jason.Encoder
|
@derive Jason.Encoder
|
||||||
|
|
||||||
# Extends from NoteValidator
|
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
field(:id, Types.ObjectID, primary_key: true)
|
field(:id, Types.ObjectID, primary_key: true)
|
||||||
field(:to, {:array, :string}, default: [])
|
field(:to, {:array, :string}, default: [])
|
||||||
field(:cc, {:array, :string}, default: [])
|
field(:cc, {:array, :string}, default: [])
|
||||||
|
|
||||||
|
# is this actually needed?
|
||||||
field(:bto, {:array, :string}, default: [])
|
field(:bto, {:array, :string}, default: [])
|
||||||
field(:bcc, {:array, :string}, default: [])
|
field(:bcc, {:array, :string}, default: [])
|
||||||
|
|
||||||
field(:type, :string)
|
field(:type, :string)
|
||||||
field(:name, :string)
|
field(:name, :string)
|
||||||
field(:inReplyTo, :string)
|
field(:inReplyTo, :string)
|
||||||
field(:attributedTo, Types.ObjectID)
|
field(:attributedTo, Types.ObjectID)
|
||||||
|
field(:actor, Types.ObjectID)
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_and_apply(data) do
|
def cast_and_apply(data) do
|
||||||
data
|
data
|
||||||
|> cast_data
|
|> cast_data()
|
||||||
|> apply_action(:insert)
|
|> apply_action(:insert)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,19 @@ def validate_actor_presence(cng, options \\ []) do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def validate_actor_is_active(cng, options \\ []) do
|
||||||
|
field_name = Keyword.get(options, :field_name, :actor)
|
||||||
|
|
||||||
|
cng
|
||||||
|
|> validate_change(field_name, fn field_name, actor ->
|
||||||
|
if %User{deactivated: false} = User.get_cached_by_ap_id(actor) do
|
||||||
|
[]
|
||||||
|
else
|
||||||
|
[{field_name, "can't find user (or deactivated)"}]
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
def validate_object_presence(cng, options \\ []) do
|
def validate_object_presence(cng, options \\ []) do
|
||||||
field_name = Keyword.get(options, :field_name, :object)
|
field_name = Keyword.get(options, :field_name, :object)
|
||||||
allowed_types = Keyword.get(options, :allowed_types, false)
|
allowed_types = Keyword.get(options, :allowed_types, false)
|
||||||
|
@ -77,4 +90,29 @@ def validate_object_or_user_presence(cng, options \\ []) do
|
||||||
|
|
||||||
if actor_cng.valid?, do: actor_cng, else: object_cng
|
if actor_cng.valid?, do: actor_cng, else: object_cng
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def validate_host_match(cng, fields \\ [:id, :actor]) do
|
||||||
|
unique_hosts =
|
||||||
|
fields
|
||||||
|
|> Enum.map(fn field ->
|
||||||
|
%URI{host: host} =
|
||||||
|
cng
|
||||||
|
|> get_field(field)
|
||||||
|
|> URI.parse()
|
||||||
|
|
||||||
|
host
|
||||||
|
end)
|
||||||
|
|> Enum.uniq()
|
||||||
|
|> Enum.count()
|
||||||
|
|
||||||
|
if unique_hosts == 1 do
|
||||||
|
cng
|
||||||
|
else
|
||||||
|
fields
|
||||||
|
|> Enum.reduce(cng, fn field, cng ->
|
||||||
|
cng
|
||||||
|
|> add_error(field, "hosts of #{inspect(fields)} aren't matching")
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,9 +4,8 @@
|
||||||
|
|
||||||
# Code based on CreateChatMessageValidator
|
# Code based on CreateChatMessageValidator
|
||||||
# NOTES
|
# NOTES
|
||||||
# - Can probably be a generic create validator
|
|
||||||
# - doesn't embed, will only get the object id
|
# - doesn't embed, will only get the object id
|
||||||
defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateQuestionValidator do
|
defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
|
@ -26,29 +25,53 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateQuestionValidator do
|
||||||
field(:object, Types.ObjectID)
|
field(:object, Types.ObjectID)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def cast_data(data) do
|
||||||
|
%__MODULE__{}
|
||||||
|
|> changeset(data)
|
||||||
|
end
|
||||||
|
|
||||||
def cast_and_apply(data) do
|
def cast_and_apply(data) do
|
||||||
data
|
data
|
||||||
|> cast_data
|
|> cast_data
|
||||||
|> apply_action(:insert)
|
|> apply_action(:insert)
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_data(data) do
|
def cast_and_validate(data, meta \\ []) do
|
||||||
cast(%__MODULE__{}, data, __schema__(:fields))
|
data
|
||||||
|
|> cast_data
|
||||||
|
|> validate_data(meta)
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_and_validate(data, meta \\ []) do
|
def changeset(struct, data) do
|
||||||
cast_data(data)
|
struct
|
||||||
|> validate_data(meta)
|
|> cast(data, __schema__(:fields))
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_data(cng, meta \\ []) do
|
def validate_data(cng, meta \\ []) do
|
||||||
cng
|
cng
|
||||||
|> validate_required([:actor, :type, :object])
|
|> validate_required([:actor, :type, :object])
|
||||||
|> validate_inclusion(:type, ["Create"])
|
|> validate_inclusion(:type, ["Create"])
|
||||||
|> validate_actor_presence()
|
|> validate_actor_is_active()
|
||||||
|> validate_any_presence([:to, :cc])
|
|> validate_any_presence([:to, :cc])
|
||||||
|> validate_actors_match(meta)
|
|> validate_actors_match(meta)
|
||||||
|> validate_object_nonexistence()
|
|> validate_object_nonexistence()
|
||||||
|
|> validate_object_containment()
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_object_containment(cng) do
|
||||||
|
actor = get_field(cng, :actor)
|
||||||
|
|
||||||
|
cng
|
||||||
|
|> validate_change(:object, fn :object, object_id ->
|
||||||
|
%URI{host: object_id_host} = URI.parse(object_id)
|
||||||
|
%URI{host: actor_host} = URI.parse(actor)
|
||||||
|
|
||||||
|
if object_id_host == actor_host do
|
||||||
|
[]
|
||||||
|
else
|
||||||
|
[{:object, "The host of the object id doesn't match with the host of the actor"}]
|
||||||
|
end
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_object_nonexistence(cng) do
|
def validate_object_nonexistence(cng) do
|
|
@ -5,6 +5,7 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do
|
defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.QuestionOptionsValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.QuestionOptionsValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.Types
|
alias Pleroma.Web.ActivityPub.ObjectValidators.Types
|
||||||
|
@ -40,13 +41,12 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do
|
||||||
field(:announcement_count, :integer, default: 0)
|
field(:announcement_count, :integer, default: 0)
|
||||||
field(:inReplyTo, :string)
|
field(:inReplyTo, :string)
|
||||||
field(:uri, Types.Uri)
|
field(:uri, Types.Uri)
|
||||||
|
# short identifier for PleromaFE to group statuses by context
|
||||||
|
field(:context_id, :integer)
|
||||||
|
|
||||||
field(:likes, {:array, :string}, default: [])
|
field(:likes, {:array, :string}, default: [])
|
||||||
field(:announcements, {:array, :string}, default: [])
|
field(:announcements, {:array, :string}, default: [])
|
||||||
|
|
||||||
# see if needed
|
|
||||||
field(:context_id, :string)
|
|
||||||
|
|
||||||
field(:closed, Types.DateTime)
|
field(:closed, Types.DateTime)
|
||||||
field(:voters, {:array, Types.ObjectID}, default: [])
|
field(:voters, {:array, Types.ObjectID}, default: [])
|
||||||
embeds_many(:anyOf, QuestionOptionsValidator)
|
embeds_many(:anyOf, QuestionOptionsValidator)
|
||||||
|
@ -70,7 +70,7 @@ def cast_data(data) do
|
||||||
|> changeset(data)
|
|> changeset(data)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fix(data) do
|
defp fix_closed(data) do
|
||||||
cond do
|
cond do
|
||||||
is_binary(data["closed"]) -> data
|
is_binary(data["closed"]) -> data
|
||||||
is_binary(data["endTime"]) -> Map.put(data, "closed", data["endTime"])
|
is_binary(data["endTime"]) -> Map.put(data, "closed", data["endTime"])
|
||||||
|
@ -78,6 +78,23 @@ def fix(data) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# based on Pleroma.Web.ActivityPub.Utils.lazy_put_objects_defaults
|
||||||
|
defp fix_defaults(data) do
|
||||||
|
%{data: %{"id" => context}, id: context_id} = Utils.create_context(data["context"])
|
||||||
|
|
||||||
|
data
|
||||||
|
|> Map.put_new_lazy("id", &Utils.generate_object_id/0)
|
||||||
|
|> Map.put_new_lazy("published", &Utils.make_date/0)
|
||||||
|
|> Map.put_new("context", context)
|
||||||
|
|> Map.put_new("context_id", context_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp fix(data) do
|
||||||
|
data
|
||||||
|
|> fix_closed()
|
||||||
|
|> fix_defaults()
|
||||||
|
end
|
||||||
|
|
||||||
def changeset(struct, data) do
|
def changeset(struct, data) do
|
||||||
data = fix(data)
|
data = fix(data)
|
||||||
|
|
||||||
|
@ -92,7 +109,8 @@ def validate_data(data_cng) do
|
||||||
|> validate_inclusion(:type, ["Question"])
|
|> validate_inclusion(:type, ["Question"])
|
||||||
|> validate_required([:id, :actor, :type, :content, :context])
|
|> validate_required([:id, :actor, :type, :content, :context])
|
||||||
|> CommonValidations.validate_any_presence([:cc, :to])
|
|> CommonValidations.validate_any_presence([:cc, :to])
|
||||||
|> CommonValidations.validate_actor_presence()
|
|> CommonValidations.validate_actor_is_active()
|
||||||
|> CommonValidations.validate_any_presence([:oneOf, :anyOf])
|
|> CommonValidations.validate_any_presence([:oneOf, :anyOf])
|
||||||
|
|> CommonValidations.validate_host_match()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
||||||
"""
|
"""
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Activity.Ir.Topics
|
alias Pleroma.Activity.Ir.Topics
|
||||||
|
alias Pleroma.ActivityExpiration
|
||||||
alias Pleroma.Chat
|
alias Pleroma.Chat
|
||||||
alias Pleroma.Chat.MessageReference
|
alias Pleroma.Chat.MessageReference
|
||||||
alias Pleroma.FollowingRelationship
|
alias Pleroma.FollowingRelationship
|
||||||
|
@ -19,6 +20,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Pleroma.Web.Push
|
alias Pleroma.Web.Push
|
||||||
alias Pleroma.Web.Streamer
|
alias Pleroma.Web.Streamer
|
||||||
|
alias Pleroma.Workers.BackgroundWorker
|
||||||
|
|
||||||
def handle(object, meta \\ [])
|
def handle(object, meta \\ [])
|
||||||
|
|
||||||
|
@ -135,10 +137,24 @@ def handle(%{data: %{"type" => "Like"}} = object, meta) do
|
||||||
# Tasks this handles
|
# Tasks this handles
|
||||||
# - Actually create object
|
# - Actually create object
|
||||||
# - Rollback if we couldn't create it
|
# - Rollback if we couldn't create it
|
||||||
|
# - Increase the user note count
|
||||||
|
# - Increase the reply count
|
||||||
# - Set up notifications
|
# - Set up notifications
|
||||||
def handle(%{data: %{"type" => "Create"}} = activity, meta) do
|
def handle(%{data: %{"type" => "Create"}} = activity, meta) do
|
||||||
with {:ok, _object, meta} <- handle_object_creation(meta[:object_data], meta) do
|
with {:ok, object, meta} <- handle_object_creation(meta[:object_data], meta),
|
||||||
|
%User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
|
||||||
{:ok, notifications} = Notification.create_notifications(activity, do_send: false)
|
{:ok, notifications} = Notification.create_notifications(activity, do_send: false)
|
||||||
|
{:ok, _user} = ActivityPub.increase_note_count_if_public(user, object)
|
||||||
|
|
||||||
|
if in_reply_to = object.data["inReplyTo"] do
|
||||||
|
Object.increase_replies_count(in_reply_to)
|
||||||
|
end
|
||||||
|
|
||||||
|
if expires_at = activity.data["expires_at"] do
|
||||||
|
ActivityExpiration.create(activity, expires_at)
|
||||||
|
end
|
||||||
|
|
||||||
|
BackgroundWorker.enqueue("fetch_data_for_activity", %{"activity_id" => activity.id})
|
||||||
|
|
||||||
meta =
|
meta =
|
||||||
meta
|
meta
|
||||||
|
@ -268,6 +284,18 @@ def handle_object_creation(%{"type" => "ChatMessage"} = object, meta) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def handle_object_creation(%{"type" => "Answer"} = object_map, meta) do
|
||||||
|
with {:ok, object, meta} <- Pipeline.common_pipeline(object_map, meta) do
|
||||||
|
Object.increase_vote_count(
|
||||||
|
object.data["inReplyTo"],
|
||||||
|
object.data["name"],
|
||||||
|
object.data["actor"]
|
||||||
|
)
|
||||||
|
|
||||||
|
{:ok, object, meta}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def handle_object_creation(%{"type" => "Question"} = object, meta) do
|
def handle_object_creation(%{"type" => "Question"} = object, meta) do
|
||||||
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
|
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
|
||||||
{:ok, object, meta}
|
{:ok, object, meta}
|
||||||
|
|
|
@ -419,6 +419,29 @@ defp get_reported(objects) do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Compatibility wrapper for Mastodon votes
|
||||||
|
defp handle_create(%{"object" => %{"type" => "Answer"}} = data, _user) do
|
||||||
|
handle_incoming(data)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_create(%{"object" => object} = data, user) do
|
||||||
|
%{
|
||||||
|
to: data["to"],
|
||||||
|
object: object,
|
||||||
|
actor: user,
|
||||||
|
context: object["context"],
|
||||||
|
local: false,
|
||||||
|
published: data["published"],
|
||||||
|
additional:
|
||||||
|
Map.take(data, [
|
||||||
|
"cc",
|
||||||
|
"directMessage",
|
||||||
|
"id"
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|> ActivityPub.create()
|
||||||
|
end
|
||||||
|
|
||||||
def handle_incoming(data, options \\ [])
|
def handle_incoming(data, options \\ [])
|
||||||
|
|
||||||
# Flag objects are placed ahead of the ID check because Mastodon 2.8 and earlier send them
|
# Flag objects are placed ahead of the ID check because Mastodon 2.8 and earlier send them
|
||||||
|
@ -461,26 +484,14 @@ def handle_incoming(
|
||||||
actor = Containment.get_actor(data)
|
actor = Containment.get_actor(data)
|
||||||
|
|
||||||
with nil <- Activity.get_create_by_object_ap_id(object["id"]),
|
with nil <- Activity.get_create_by_object_ap_id(object["id"]),
|
||||||
{:ok, %User{} = user} <- User.get_or_fetch_by_ap_id(actor),
|
{:ok, %User{} = user} <- User.get_or_fetch_by_ap_id(actor) do
|
||||||
data <- Map.put(data, "actor", actor) |> fix_addressing() do
|
data =
|
||||||
object = fix_object(object, options)
|
data
|
||||||
|
|> Map.put("object", fix_object(object, options))
|
||||||
|
|> Map.put("actor", actor)
|
||||||
|
|> fix_addressing()
|
||||||
|
|
||||||
params = %{
|
with {:ok, created_activity} <- handle_create(data, user) do
|
||||||
to: data["to"],
|
|
||||||
object: object,
|
|
||||||
actor: user,
|
|
||||||
context: object["context"],
|
|
||||||
local: false,
|
|
||||||
published: data["published"],
|
|
||||||
additional:
|
|
||||||
Map.take(data, [
|
|
||||||
"cc",
|
|
||||||
"directMessage",
|
|
||||||
"id"
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
with {:ok, created_activity} <- ActivityPub.create(params) do
|
|
||||||
reply_depth = (options[:depth] || 0) + 1
|
reply_depth = (options[:depth] || 0) + 1
|
||||||
|
|
||||||
if Federator.allowed_thread_distance?(reply_depth) do
|
if Federator.allowed_thread_distance?(reply_depth) do
|
||||||
|
|
|
@ -308,18 +308,19 @@ def vote(user, %{data: %{"type" => "Question"}} = object, choices) do
|
||||||
{:ok, options, choices} <- normalize_and_validate_choices(choices, object) do
|
{:ok, options, choices} <- normalize_and_validate_choices(choices, object) do
|
||||||
answer_activities =
|
answer_activities =
|
||||||
Enum.map(choices, fn index ->
|
Enum.map(choices, fn index ->
|
||||||
answer_data = make_answer_data(user, object, Enum.at(options, index)["name"])
|
{:ok, answer_object, _meta} =
|
||||||
|
Builder.answer(user, object, Enum.at(options, index)["name"])
|
||||||
|
|
||||||
{:ok, activity} =
|
{:ok, activity_data, _meta} = Builder.create(user, answer_object, [])
|
||||||
ActivityPub.create(%{
|
|
||||||
to: answer_data["to"],
|
|
||||||
actor: user,
|
|
||||||
context: object.data["context"],
|
|
||||||
object: answer_data,
|
|
||||||
additional: %{"cc" => answer_data["cc"]}
|
|
||||||
})
|
|
||||||
|
|
||||||
activity
|
{:ok, activity, _meta} =
|
||||||
|
activity_data
|
||||||
|
|> Map.put("cc", answer_object["cc"])
|
||||||
|
|> Map.put("context", answer_object["context"])
|
||||||
|
|> Pipeline.common_pipeline(local: true)
|
||||||
|
|
||||||
|
# TODO: Do preload of Pleroma.Object in Pipeline
|
||||||
|
Activity.normalize(activity.data)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
object = Object.get_cached_by_ap_id(object.data["id"])
|
object = Object.get_cached_by_ap_id(object.data["id"])
|
||||||
|
|
|
@ -548,17 +548,6 @@ def conversation_id_to_context(id) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_answer_data(%User{ap_id: ap_id}, object, name) do
|
|
||||||
%{
|
|
||||||
"type" => "Answer",
|
|
||||||
"actor" => ap_id,
|
|
||||||
"cc" => [object.data["actor"]],
|
|
||||||
"to" => [],
|
|
||||||
"name" => name,
|
|
||||||
"inReplyTo" => object.data["id"]
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def validate_character_limit("" = _full_payload, [] = _attachments) do
|
def validate_character_limit("" = _full_payload, [] = _attachments) do
|
||||||
{:error, dgettext("errors", "Cannot post an empty status without attachments")}
|
{:error, dgettext("errors", "Cannot post an empty status without attachments")}
|
||||||
end
|
end
|
||||||
|
|
|
@ -282,7 +282,7 @@ test "it works for incoming listens" do
|
||||||
assert object.data["length"] == 180_000
|
assert object.data["length"] == 180_000
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it rewrites Note votes to Answers and increments vote counters on question activities" do
|
test "it rewrites Note votes to Answer and increments vote counters on Question activities" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
{:ok, activity} =
|
{:ok, activity} =
|
||||||
|
|
Loading…
Reference in New Issue