Merge branch 'feature/emojireactvalidator' into 'develop'
Move EmojiReacts to the Pipeline. See merge request pleroma/pleroma!2473
This commit is contained in:
commit
fbcc53760e
19 changed files with 276 additions and 169 deletions
|
|
@ -356,31 +356,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
end
|
||||
|
||||
@spec react_with_emoji(User.t(), Object.t(), String.t(), keyword()) ::
|
||||
{:ok, Activity.t(), Object.t()} | {:error, any()}
|
||||
def react_with_emoji(user, object, emoji, options \\ []) do
|
||||
with {:ok, result} <-
|
||||
Repo.transaction(fn -> do_react_with_emoji(user, object, emoji, options) end) do
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
defp do_react_with_emoji(user, object, emoji, options) do
|
||||
with local <- Keyword.get(options, :local, true),
|
||||
activity_id <- Keyword.get(options, :activity_id, nil),
|
||||
true <- Pleroma.Emoji.is_unicode_emoji?(emoji),
|
||||
reaction_data <- make_emoji_reaction_data(user, object, emoji, activity_id),
|
||||
{:ok, activity} <- insert(reaction_data, local),
|
||||
{:ok, object} <- add_emoji_reaction_to_object(activity, object),
|
||||
_ <- notify_and_stream(activity),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity, object}
|
||||
else
|
||||
false -> {:error, false}
|
||||
{:error, error} -> Repo.rollback(error)
|
||||
end
|
||||
end
|
||||
|
||||
@spec announce(User.t(), Object.t(), String.t() | nil, boolean(), boolean()) ::
|
||||
{:ok, Activity.t(), Object.t()} | {:error, any()}
|
||||
def announce(
|
||||
|
|
|
|||
|
|
@ -10,6 +10,18 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|
|||
alias Pleroma.Web.ActivityPub.Utils
|
||||
alias Pleroma.Web.ActivityPub.Visibility
|
||||
|
||||
@spec emoji_react(User.t(), Object.t(), String.t()) :: {:ok, map(), keyword()}
|
||||
def emoji_react(actor, object, emoji) do
|
||||
with {:ok, data, meta} <- object_action(actor, object) do
|
||||
data =
|
||||
data
|
||||
|> Map.put("content", emoji)
|
||||
|> Map.put("type", "EmojiReact")
|
||||
|
||||
{:ok, data, meta}
|
||||
end
|
||||
end
|
||||
|
||||
@spec undo(User.t(), Activity.t()) :: {:ok, map(), keyword()}
|
||||
def undo(actor, object) do
|
||||
{:ok,
|
||||
|
|
@ -52,6 +64,17 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|
|||
|
||||
@spec like(User.t(), Object.t()) :: {:ok, map(), keyword()}
|
||||
def like(actor, object) do
|
||||
with {:ok, data, meta} <- object_action(actor, object) do
|
||||
data =
|
||||
data
|
||||
|> Map.put("type", "Like")
|
||||
|
||||
{:ok, data, meta}
|
||||
end
|
||||
end
|
||||
|
||||
@spec object_action(User.t(), Object.t()) :: {:ok, map(), keyword()}
|
||||
defp object_action(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.
|
||||
|
|
@ -73,7 +96,6 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|
|||
%{
|
||||
"id" => Utils.generate_activity_id(),
|
||||
"actor" => actor.ap_id,
|
||||
"type" => "Like",
|
||||
"object" => object.data["id"],
|
||||
"to" => to,
|
||||
"cc" => cc,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
|||
alias Pleroma.Object
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator
|
||||
alias Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator
|
||||
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
|
||||
alias Pleroma.Web.ActivityPub.ObjectValidators.Types
|
||||
alias Pleroma.Web.ActivityPub.ObjectValidators.UndoValidator
|
||||
|
|
@ -47,6 +48,16 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
|||
end
|
||||
end
|
||||
|
||||
def validate(%{"type" => "EmojiReact"} = object, meta) do
|
||||
with {:ok, object} <-
|
||||
object
|
||||
|> EmojiReactValidator.cast_and_validate()
|
||||
|> Ecto.Changeset.apply_action(:insert) do
|
||||
object = stringify_keys(object |> Map.from_struct())
|
||||
{:ok, object, meta}
|
||||
end
|
||||
end
|
||||
|
||||
def stringify_keys(%{__struct__: _} = object) do
|
||||
object
|
||||
|> Map.from_struct()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
|
||||
use Ecto.Schema
|
||||
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Web.ActivityPub.ObjectValidators.Types
|
||||
|
||||
import Ecto.Changeset
|
||||
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
||||
|
||||
@primary_key false
|
||||
|
||||
embedded_schema do
|
||||
field(:id, Types.ObjectID, primary_key: true)
|
||||
field(:type, :string)
|
||||
field(:object, Types.ObjectID)
|
||||
field(:actor, Types.ObjectID)
|
||||
field(:context, :string)
|
||||
field(:content, :string)
|
||||
field(:to, {:array, :string}, default: [])
|
||||
field(:cc, {:array, :string}, default: [])
|
||||
end
|
||||
|
||||
def cast_and_validate(data) do
|
||||
data
|
||||
|> cast_data()
|
||||
|> validate_data()
|
||||
end
|
||||
|
||||
def cast_data(data) do
|
||||
%__MODULE__{}
|
||||
|> changeset(data)
|
||||
end
|
||||
|
||||
def changeset(struct, data) do
|
||||
struct
|
||||
|> cast(data, __schema__(:fields))
|
||||
|> fix_after_cast()
|
||||
end
|
||||
|
||||
def fix_after_cast(cng) do
|
||||
cng
|
||||
|> fix_context()
|
||||
end
|
||||
|
||||
def fix_context(cng) do
|
||||
object = get_field(cng, :object)
|
||||
|
||||
with nil <- get_field(cng, :context),
|
||||
%Object{data: %{"context" => context}} <- Object.get_cached_by_ap_id(object) do
|
||||
cng
|
||||
|> put_change(:context, context)
|
||||
else
|
||||
_ ->
|
||||
cng
|
||||
end
|
||||
end
|
||||
|
||||
def validate_emoji(cng) do
|
||||
content = get_field(cng, :content)
|
||||
|
||||
if Pleroma.Emoji.is_unicode_emoji?(content) do
|
||||
cng
|
||||
else
|
||||
cng
|
||||
|> add_error(:content, "must be a single character emoji")
|
||||
end
|
||||
end
|
||||
|
||||
def validate_data(data_cng) do
|
||||
data_cng
|
||||
|> validate_inclusion(:type, ["EmojiReact"])
|
||||
|> validate_required([:id, :type, :object, :actor, :context, :to, :cc, :content])
|
||||
|> validate_actor_presence()
|
||||
|> validate_object_presence()
|
||||
|> validate_emoji()
|
||||
end
|
||||
end
|
||||
|
|
@ -34,6 +34,18 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
|||
end
|
||||
end
|
||||
|
||||
# Tasks this handles:
|
||||
# - Add reaction to object
|
||||
# - Set up notification
|
||||
def handle(%{data: %{"type" => "EmojiReact"}} = object, meta) do
|
||||
reacted_object = Object.get_by_ap_id(object.data["object"])
|
||||
Utils.add_emoji_reaction_to_object(object, reacted_object)
|
||||
|
||||
Notification.create_notifications(object)
|
||||
|
||||
{:ok, object, meta}
|
||||
end
|
||||
|
||||
# Tasks this handles:
|
||||
# - Delete and unpins the create activity
|
||||
# - Replace object with Tombstone
|
||||
|
|
|
|||
|
|
@ -656,7 +656,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|> handle_incoming(options)
|
||||
end
|
||||
|
||||
def handle_incoming(%{"type" => "Like"} = data, _options) do
|
||||
def handle_incoming(%{"type" => type} = data, _options) when type in ["Like", "EmojiReact"] do
|
||||
with :ok <- ObjectValidator.fetch_actor_and_object(data),
|
||||
{:ok, activity, _meta} <-
|
||||
Pipeline.common_pipeline(data, local: false) do
|
||||
|
|
@ -666,27 +666,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
end
|
||||
end
|
||||
|
||||
def handle_incoming(
|
||||
%{
|
||||
"type" => "EmojiReact",
|
||||
"object" => object_id,
|
||||
"actor" => _actor,
|
||||
"id" => id,
|
||||
"content" => emoji
|
||||
} = 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.react_with_emoji(actor, object, emoji, activity_id: id, local: false) do
|
||||
{:ok, activity}
|
||||
else
|
||||
_e -> :error
|
||||
end
|
||||
end
|
||||
|
||||
def handle_incoming(
|
||||
%{"type" => "Announce", "object" => object_id, "actor" => _actor, "id" => id} = data,
|
||||
_options
|
||||
|
|
|
|||
|
|
@ -191,8 +191,10 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
|
||||
def react_with_emoji(id, user, emoji) do
|
||||
with %Activity{} = activity <- Activity.get_by_id(id),
|
||||
object <- Object.normalize(activity) do
|
||||
ActivityPub.react_with_emoji(user, object, emoji)
|
||||
object <- Object.normalize(activity),
|
||||
{:ok, emoji_react, _} <- Builder.emoji_react(user, object, emoji),
|
||||
{:ok, activity, _} <- Pipeline.common_pipeline(emoji_react, local: true) do
|
||||
{:ok, activity}
|
||||
else
|
||||
_ ->
|
||||
{:error, dgettext("errors", "Could not add reaction emoji")}
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
|
|||
end
|
||||
|
||||
def react_with_emoji(%{assigns: %{user: user}} = conn, %{"id" => activity_id, "emoji" => emoji}) do
|
||||
with {:ok, _activity, _object} <- CommonAPI.react_with_emoji(activity_id, user, emoji),
|
||||
with {:ok, _activity} <- CommonAPI.react_with_emoji(activity_id, user, emoji),
|
||||
activity <- Activity.get_by_id(activity_id) do
|
||||
conn
|
||||
|> put_view(StatusView)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue