Merge branch 'announce-validator' into 'develop'

Announce validator

See merge request pleroma/pleroma!2567
This commit is contained in:
Haelwenn 2020-05-22 05:47:53 +00:00
commit 7b02bfca51
33 changed files with 796 additions and 367 deletions

View File

@ -356,36 +356,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end end
end end
@spec announce(User.t(), Object.t(), String.t() | nil, boolean(), boolean()) ::
{:ok, Activity.t(), Object.t()} | {:error, any()}
def announce(
%User{ap_id: _} = user,
%Object{data: %{"id" => _}} = object,
activity_id \\ nil,
local \\ true,
public \\ true
) do
with {:ok, result} <-
Repo.transaction(fn -> do_announce(user, object, activity_id, local, public) end) do
result
end
end
defp do_announce(user, object, activity_id, local, public) do
with true <- is_announceable?(object, user, public),
object <- Object.get_by_id(object.id),
announce_data <- make_announce_data(user, object, activity_id, public),
{:ok, activity} <- insert(announce_data, local),
{:ok, object} <- add_announce_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 follow(User.t(), User.t(), String.t() | nil, boolean()) :: @spec follow(User.t(), User.t(), String.t() | nil, boolean()) ::
{:ok, Activity.t()} | {:error, any()} {:ok, Activity.t()} | {:error, any()}
def follow(follower, followed, activity_id \\ nil, local \\ true) do def follow(follower, followed, activity_id \\ nil, local \\ true) do

View File

@ -10,6 +10,8 @@ defmodule Pleroma.Web.ActivityPub.Builder do
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.ActivityPub.Visibility
require Pleroma.Constants
@spec emoji_react(User.t(), Object.t(), String.t()) :: {:ok, map(), keyword()} @spec emoji_react(User.t(), Object.t(), String.t()) :: {:ok, map(), keyword()}
def emoji_react(actor, object, emoji) do def emoji_react(actor, object, emoji) do
with {:ok, data, meta} <- object_action(actor, object) do with {:ok, data, meta} <- object_action(actor, object) do
@ -83,6 +85,29 @@ defmodule Pleroma.Web.ActivityPub.Builder do
end end
end end
def announce(actor, object, options \\ []) do
public? = Keyword.get(options, :public, false)
to = [actor.follower_address, object.data["actor"]]
to =
if public? do
[Pleroma.Constants.as_public() | to]
else
to
end
{:ok,
%{
"id" => Utils.generate_activity_id(),
"actor" => actor.ap_id,
"object" => object.data["id"],
"to" => to,
"context" => object.data["context"],
"type" => "Announce",
"published" => Utils.make_date()
}, []}
end
@spec object_action(User.t(), Object.t()) :: {:ok, map(), keyword()} @spec object_action(User.t(), Object.t()) :: {:ok, map(), keyword()}
defp object_action(actor, object) do defp object_action(actor, object) do
object_actor = User.get_cached_by_ap_id(object.data["actor"]) object_actor = User.get_cached_by_ap_id(object.data["actor"])

View File

@ -11,6 +11,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator
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.LikeValidator alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
@ -58,6 +59,16 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
end end
end end
def validate(%{"type" => "Announce"} = object, meta) do
with {:ok, object} <-
object
|> AnnounceValidator.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 def stringify_keys(%{__struct__: _} = object) do
object object
|> Map.from_struct() |> Map.from_struct()
@ -77,7 +88,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
def fetch_actor_and_object(object) do def fetch_actor_and_object(object) do
fetch_actor(object) fetch_actor(object)
Object.normalize(object["object"]) Object.normalize(object["object"], true)
:ok :ok
end end
end end

View File

@ -0,0 +1,101 @@
# 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.AnnounceValidator do
use Ecto.Schema
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ObjectValidators.Types
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
import Ecto.Changeset
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
require Pleroma.Constants
@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, autogenerate: {Utils, :generate_context_id, []})
field(:to, Types.Recipients, default: [])
field(:cc, Types.Recipients, default: [])
field(:published, Types.DateTime)
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
end
def validate_data(data_cng) do
data_cng
|> validate_inclusion(:type, ["Announce"])
|> validate_required([:id, :type, :object, :actor, :to, :cc])
|> validate_actor_presence()
|> validate_object_presence()
|> validate_existing_announce()
|> validate_announcable()
end
def validate_announcable(cng) do
with actor when is_binary(actor) <- get_field(cng, :actor),
object when is_binary(object) <- get_field(cng, :object),
%User{} = actor <- User.get_cached_by_ap_id(actor),
%Object{} = object <- Object.get_cached_by_ap_id(object),
false <- Visibility.is_public?(object) do
same_actor = object.data["actor"] == actor.ap_id
is_public = Pleroma.Constants.as_public() in (get_field(cng, :to) ++ get_field(cng, :cc))
cond do
same_actor && is_public ->
cng
|> add_error(:actor, "can not announce this object publicly")
!same_actor ->
cng
|> add_error(:actor, "can not announce this object")
true ->
cng
end
else
_ -> cng
end
end
def validate_existing_announce(cng) do
actor = get_field(cng, :actor)
object = get_field(cng, :object)
if actor && object && Utils.get_existing_announce(actor, %{data: %{"id" => object}}) do
cng
|> add_error(:actor, "already announced this object")
|> add_error(:object, "already announced by this actor")
else
cng
end
end
end

View File

@ -4,6 +4,7 @@
defmodule Pleroma.Web.ActivityPub.Pipeline do defmodule Pleroma.Web.ActivityPub.Pipeline do
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Config
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Repo alias Pleroma.Repo
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
@ -44,7 +45,7 @@ defmodule Pleroma.Web.ActivityPub.Pipeline do
defp maybe_federate(%Activity{} = activity, meta) do defp maybe_federate(%Activity{} = activity, meta) do
with {:ok, local} <- Keyword.fetch(meta, :local) do with {:ok, local} <- Keyword.fetch(meta, :local) do
do_not_federate = meta[:do_not_federate] do_not_federate = meta[:do_not_federate] || !Config.get([:instance, :federating])
if !do_not_federate && local do if !do_not_federate && local do
Federator.publish(activity) Federator.publish(activity)

View File

@ -4,9 +4,10 @@
defmodule Pleroma.Web.ActivityPub.Relay do defmodule Pleroma.Web.ActivityPub.Relay do
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.CommonAPI
require Logger require Logger
@relay_nickname "relay" @relay_nickname "relay"
@ -48,11 +49,11 @@ defmodule Pleroma.Web.ActivityPub.Relay do
end end
end end
@spec publish(any()) :: {:ok, Activity.t(), Object.t()} | {:error, any()} @spec publish(any()) :: {:ok, Activity.t()} | {:error, any()}
def publish(%Activity{data: %{"type" => "Create"}} = activity) do def publish(%Activity{data: %{"type" => "Create"}} = activity) do
with %User{} = user <- get_actor(), with %User{} = user <- get_actor(),
%Object{} = object <- Object.normalize(activity) do true <- Visibility.is_public?(activity) do
ActivityPub.announce(user, object, nil, true, false) CommonAPI.repeat(activity.id, user)
else else
error -> format_error(error) error -> format_error(error)
end end

View File

@ -27,6 +27,21 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
{:ok, object, meta} {:ok, object, meta}
end end
# Tasks this handles:
# - Add announce to object
# - Set up notification
# - Stream out the announce
def handle(%{data: %{"type" => "Announce"}} = object, meta) do
announced_object = Object.get_by_ap_id(object.data["object"])
Utils.add_announce_to_object(object, announced_object)
Notification.create_notifications(object)
ActivityPub.stream_out(object)
{:ok, object, meta}
end
def handle(%{data: %{"type" => "Undo", "object" => undone_object}} = object, meta) do def handle(%{data: %{"type" => "Undo", "object" => undone_object}} = object, meta) do
with undone_object <- Activity.get_by_ap_id(undone_object), with undone_object <- Activity.get_by_ap_id(undone_object),
:ok <- handle_undoing(undone_object) do :ok <- handle_undoing(undone_object) do

View File

@ -662,7 +662,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> handle_incoming(options) |> handle_incoming(options)
end end
def handle_incoming(%{"type" => type} = data, _options) when type in ["Like", "EmojiReact"] do def handle_incoming(%{"type" => type} = data, _options)
when type in ["Like", "EmojiReact", "Announce"] do
with :ok <- ObjectValidator.fetch_actor_and_object(data), with :ok <- ObjectValidator.fetch_actor_and_object(data),
{:ok, activity, _meta} <- {:ok, activity, _meta} <-
Pipeline.common_pipeline(data, local: false) do Pipeline.common_pipeline(data, local: false) do
@ -672,21 +673,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end end
end end
def handle_incoming(
%{"type" => "Announce", "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_embedded_obj_helper(object_id, actor),
public <- Visibility.is_public?(data),
{:ok, activity, _object} <- ActivityPub.announce(actor, object, id, false, public) do
{:ok, activity}
else
_e -> :error
end
end
def handle_incoming( def handle_incoming(
%{"type" => "Update", "object" => %{"type" => object_type} = object, "actor" => actor_id} = %{"type" => "Update", "object" => %{"type" => object_type} = object, "actor" => actor_id} =
data, data,

View File

@ -127,18 +127,19 @@ defmodule Pleroma.Web.CommonAPI do
end end
def repeat(id, user, params \\ %{}) do def repeat(id, user, params \\ %{}) do
with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id(id) do with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id(id),
object = Object.normalize(activity) object = %Object{} <- Object.normalize(activity, false),
announce_activity = Utils.get_existing_announce(user.ap_id, object) {_, nil} <- {:existing_announce, Utils.get_existing_announce(user.ap_id, object)},
public = public_announce?(object, params) public = public_announce?(object, params),
{:ok, announce, _} <- Builder.announce(user, object, public: public),
{:ok, activity, _} <- Pipeline.common_pipeline(announce, local: true) do
{:ok, activity}
else
{:existing_announce, %Activity{} = announce} ->
{:ok, announce}
if announce_activity do _ ->
{:ok, announce_activity, object} {:error, :not_found}
else
ActivityPub.announce(user, object, nil, true, public)
end
else
_ -> {:error, :not_found}
end end
end end

View File

@ -210,7 +210,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
@doc "POST /api/v1/statuses/:id/reblog" @doc "POST /api/v1/statuses/:id/reblog"
def reblog(%{assigns: %{user: user}, body_params: params} = conn, %{id: ap_id_or_id}) do def reblog(%{assigns: %{user: user}, body_params: params} = conn, %{id: ap_id_or_id}) do
with {:ok, announce, _activity} <- CommonAPI.repeat(ap_id_or_id, user, params), with {:ok, announce} <- CommonAPI.repeat(ap_id_or_id, user, params),
%Activity{} = announce <- Activity.normalize(announce.data) do %Activity{} = announce <- Activity.normalize(announce.data) do
try_render(conn, "show.json", %{activity: announce, for: user, as: :activity}) try_render(conn, "show.json", %{activity: announce, for: user, as: :activity})
end end

View File

@ -1 +1,88 @@
{"@context":["https://www.w3.org/ns/activitystreams","https://puckipedia.com/-/context"],"actor":{"endpoints":"https://puckipedia.com/#endpoints","followers":"https://puckipedia.com/followers","following":"https://puckipedia.com/following","icon":{"mediaType":"image/png","type":"Image","url":"https://puckipedia.com/images/avatar.png"},"id":"https://puckipedia.com/","inbox":"https://puckipedia.com/inbox","kroeg:blocks":{"id":"https://puckipedia.com/blocks"},"liked":"https://puckipedia.com/liked","manuallyApprovesFollowers":false,"name":"HACKER TEEN PUCKIPEDIA 👩‍💻","outbox":"https://puckipedia.com/outbox","preferredUsername":"puckipedia","publicKey":{"id":"https://puckipedia.com/#key","owner":"https://puckipedia.com/","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvN05xIcFE0Qgany7Rht4\n0ZI5wu++IT7K5iSqRimBYkpoeHbVcT9RFlW+aWH/QJJW/YgZ7+LMr8AMCrKrwSpS\nCndyrpx4O4lZ3FNRLu7tbklh01rGZfE6R1SFfYBpvMvImc9nYT6iezYDbv6NkHku\no3aVhjql216XlA0OhIrqQme9sAdrLbjbMrTUS8douCTkDOX+JFj1ghHCqdYEMZJI\nOY9kovtgnqyxFLm0RsPGsO1+g/OVojqG+VqHz6O2lceaTVQLlnZ4gOhLVG1tVsA2\nRfXQK+R/VgXncYE+BlQVd/tcdGAz7CDL7PP3rP65gmARnafhGR96cCOi/KzlAXSO\nMwIDAQAB\n-----END PUBLIC KEY-----","type":[]},"summary":"<p>federated hacker teen<br/>\n[<a href=\"https://pronoun.is/she\">she</a>/<a href=\"https://pronoun.is/they\">they</a>]</p>","type":"Person","updated":"2017-12-19T16:56:29.7576707+00:00"},"cc":"http://mastodon.example.org/users/admin","id":"https://puckipedia.com/cc56a9658e","object":{"as:sensitive":false,"attributedTo":{"endpoints":{"sharedInbox":"https://mastodon.social/inbox","type":[]},"followers":"http://mastodon.example.org/users/admin/followers","following":"http://mastodon.example.org/users/admin/following","icon":{"mediaType":"image/png","type":"Image","url":"https://files.mastodon.social/accounts/avatars/000/015/163/original/70ca6c52b01ca913.png"},"id":"http://mastodon.example.org/users/admin","inbox":"http://mastodon.example.org/users/admin/inbox","manuallyApprovesFollowers":{"@value":"False","type":"xsd:boolean"},"name":"","outbox":"http://mastodon.example.org/users/admin/outbox","preferredUsername":"revenant","publicKey":{"id":"http://mastodon.example.org/users/admin#main-key","owner":"http://mastodon.example.org/users/admin","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0gEN3wPW7gkE2gQqnmfB\n1ychjmFIf2LIwY0oCJLiGE/xpZrUKoq+eWH30AP7mATw4LD0gOYABL/ijqPUrPqR\nDXLL+0CqMP8HsZKvRlj9KArMK3YtNiSGGj2U7iReiRrD7nJzjJlsjjJXflLZhZ7/\nenSv1CcaeK8tB0PoAgShy/MyfhPF7WI5/Zm9DmmDQFvUEnDYKXAf/vG/IWw1EyMC\nkbaEYJeIowQU3GsbPxzRGI22bQtfotm431Ch2MbNo+kyzmYVFLAVoSGNMzvJwOPg\nTxLIIBeQXG7MinRyK887yPKhxhcALea4yCcALaa+3jPE7yqwIKYwTHtSlblsHDAo\nmQIDAQAB\n-----END PUBLIC KEY-----\n","type":[]},"summary":"<p>neatly partitioned meats and cheeses appeal to me on an aesthetic level | any pronouns | revenant1.net</p>","type":"Person","url":"https://mastodon.social/@revenant"},"cc":"http://mastodon.example.org/users/admin/followers","content":"<p>the name&apos;s jond (jeans bond)</p>","contentMap":{"en":"<p>the name&apos;s jond (jeans bond)</p>"},"conversation":"tag:mastodon.social,2018-09-25:objectId=55659382:objectType=Conversation","id":"http://mastodon.example.org/users/admin/statuses/100787282858396771","ostatus:atomUri":"http://mastodon.example.org/users/admin/statuses/100787282858396771","published":"2018-09-25T16:11:29Z","to":"https://www.w3.org/ns/activitystreams#Public","type":"Note","url":"https://mastodon.social/@revenant/100787282858396771"},"to":["https://www.w3.org/ns/activitystreams#Public","https://puckipedia.com/followers"],"type":"Announce"} {
"@context" : [
"https://www.w3.org/ns/activitystreams",
"https://puckipedia.com/-/context"
],
"actor" : {
"endpoints" : "https://puckipedia.com/#endpoints",
"followers" : "https://puckipedia.com/followers",
"following" : "https://puckipedia.com/following",
"icon" : {
"mediaType" : "image/png",
"type" : "Image",
"url" : "https://puckipedia.com/images/avatar.png"
},
"id" : "https://puckipedia.com/",
"inbox" : "https://puckipedia.com/inbox",
"kroeg:blocks" : {
"id" : "https://puckipedia.com/blocks"
},
"liked" : "https://puckipedia.com/liked",
"manuallyApprovesFollowers" : false,
"name" : "HACKER TEEN PUCKIPEDIA 👩‍💻",
"outbox" : "https://puckipedia.com/outbox",
"preferredUsername" : "puckipedia",
"publicKey" : {
"id" : "https://puckipedia.com/#key",
"owner" : "https://puckipedia.com/",
"publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvN05xIcFE0Qgany7Rht4\n0ZI5wu++IT7K5iSqRimBYkpoeHbVcT9RFlW+aWH/QJJW/YgZ7+LMr8AMCrKrwSpS\nCndyrpx4O4lZ3FNRLu7tbklh01rGZfE6R1SFfYBpvMvImc9nYT6iezYDbv6NkHku\no3aVhjql216XlA0OhIrqQme9sAdrLbjbMrTUS8douCTkDOX+JFj1ghHCqdYEMZJI\nOY9kovtgnqyxFLm0RsPGsO1+g/OVojqG+VqHz6O2lceaTVQLlnZ4gOhLVG1tVsA2\nRfXQK+R/VgXncYE+BlQVd/tcdGAz7CDL7PP3rP65gmARnafhGR96cCOi/KzlAXSO\nMwIDAQAB\n-----END PUBLIC KEY-----",
"type" : []
},
"summary" : "<p>federated hacker teen<br/>\n[<a href=\"https://pronoun.is/she\">she</a>/<a href=\"https://pronoun.is/they\">they</a>]</p>",
"type" : "Person",
"updated" : "2017-12-19T16:56:29.7576707+00:00"
},
"cc" : "http://mastodon.example.org/users/admin",
"id" : "https://puckipedia.com/cc56a9658e",
"object" : {
"as:sensitive" : false,
"attributedTo" : {
"endpoints" : {
"sharedInbox" : "https://mastodon.social/inbox",
"type" : []
},
"followers" : "http://mastodon.example.org/users/admin/followers",
"following" : "http://mastodon.example.org/users/admin/following",
"icon" : {
"mediaType" : "image/png",
"type" : "Image",
"url" : "https://files.mastodon.social/accounts/avatars/000/015/163/original/70ca6c52b01ca913.png"
},
"id" : "http://mastodon.example.org/users/admin",
"inbox" : "http://mastodon.example.org/users/admin/inbox",
"manuallyApprovesFollowers" : {
"@value" : "False",
"type" : "xsd:boolean"
},
"name" : "",
"outbox" : "http://mastodon.example.org/users/admin/outbox",
"preferredUsername" : "revenant",
"publicKey" : {
"id" : "http://mastodon.example.org/users/admin#main-key",
"owner" : "http://mastodon.example.org/users/admin",
"publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0gEN3wPW7gkE2gQqnmfB\n1ychjmFIf2LIwY0oCJLiGE/xpZrUKoq+eWH30AP7mATw4LD0gOYABL/ijqPUrPqR\nDXLL+0CqMP8HsZKvRlj9KArMK3YtNiSGGj2U7iReiRrD7nJzjJlsjjJXflLZhZ7/\nenSv1CcaeK8tB0PoAgShy/MyfhPF7WI5/Zm9DmmDQFvUEnDYKXAf/vG/IWw1EyMC\nkbaEYJeIowQU3GsbPxzRGI22bQtfotm431Ch2MbNo+kyzmYVFLAVoSGNMzvJwOPg\nTxLIIBeQXG7MinRyK887yPKhxhcALea4yCcALaa+3jPE7yqwIKYwTHtSlblsHDAo\nmQIDAQAB\n-----END PUBLIC KEY-----\n",
"type" : []
},
"summary" : "<p>neatly partitioned meats and cheeses appeal to me on an aesthetic level | any pronouns | revenant1.net</p>",
"type" : "Person",
"url" : "https://mastodon.social/@revenant"
},
"cc" : "http://mastodon.example.org/users/admin/followers",
"content" : "<p>the name&apos;s jond (jeans bond)</p>",
"contentMap" : {
"en" : "<p>the name&apos;s jond (jeans bond)</p>"
},
"conversation" : "tag:mastodon.social,2018-09-25:objectId=55659382:objectType=Conversation",
"id" : "http://mastodon.example.org/users/admin/statuses/100787282858396771",
"ostatus:atomUri" : "http://mastodon.example.org/users/admin/statuses/100787282858396771",
"published" : "2018-09-25T16:11:29Z",
"to" : "https://www.w3.org/ns/activitystreams#Public",
"type" : "Note",
"url" : "https://mastodon.social/@revenant/100787282858396771"
},
"to" : [
"https://www.w3.org/ns/activitystreams#Public",
"https://puckipedia.com/followers"
],
"type" : "Announce"
}

View File

@ -1,9 +1,45 @@
{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1",{"manuallyApprovesFollowers":"as:manuallyApprovesFollowers","sensitive":"as:sensitive","movedTo":"as:movedTo","Hashtag":"as:Hashtag","ostatus":"http://ostatus.org#","atomUri":"ostatus:atomUri","inReplyToAtomUri":"ostatus:inReplyToAtomUri","conversation":"ostatus:conversation","toot":"http://joinmastodon.org/ns#","Emoji":"toot:Emoji"}],"id":"http://mastodon.example.org/users/admin/statuses/99541947525187367","type":"Note","summary":null,"content":"\u003cp\u003eyeah.\u003c/p\u003e","inReplyTo":null,"published":"2018-02-17T17:46:20Z","url":"http://mastodon.example.org/@admin/99541947525187367","attributedTo":"http://mastodon.example.org/users/admin","to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["http://mastodon.example.org/users/admin/followers"],"sensitive":false,"atomUri":"http://mastodon.example.org/users/admin/statuses/99541947525187367","inReplyToAtomUri":null,"conversation":"tag:mastodon.example.org,2018-02-17:objectId=59:objectType=Conversation","tag":[], {
"attachment": [ "@context" : [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{ {
"url": "http://mastodon.example.org/system/media_attachments/files/000/000/002/original/334ce029e7bfb920.jpg", "Emoji" : "toot:Emoji",
"type": "Document", "Hashtag" : "as:Hashtag",
"name": null, "atomUri" : "ostatus:atomUri",
"mediaType": "image/jpeg" "conversation" : "ostatus:conversation",
"inReplyToAtomUri" : "ostatus:inReplyToAtomUri",
"manuallyApprovesFollowers" : "as:manuallyApprovesFollowers",
"movedTo" : "as:movedTo",
"ostatus" : "http://ostatus.org#",
"sensitive" : "as:sensitive",
"toot" : "http://joinmastodon.org/ns#"
} }
]} ],
"atomUri" : "http://mastodon.example.org/users/admin/statuses/99541947525187367",
"attachment" : [
{
"mediaType" : "image/jpeg",
"name" : null,
"type" : "Document",
"url" : "http://mastodon.example.org/system/media_attachments/files/000/000/002/original/334ce029e7bfb920.jpg"
}
],
"attributedTo" : "http://mastodon.example.org/users/admin",
"cc" : [
"http://mastodon.example.org/users/admin/followers"
],
"content" : "<p>yeah.</p>",
"conversation" : "tag:mastodon.example.org,2018-02-17:objectId=59:objectType=Conversation",
"id" : "http://mastodon.example.org/users/admin/statuses/99541947525187367",
"inReplyTo" : null,
"inReplyToAtomUri" : null,
"published" : "2018-02-17T17:46:20Z",
"sensitive" : false,
"summary" : null,
"tag" : [],
"to" : [
"https://www.w3.org/ns/activitystreams#Public"
],
"type" : "Note",
"url" : "http://mastodon.example.org/@admin/99541947525187367"
}

View File

@ -648,7 +648,7 @@ defmodule Pleroma.NotificationTest do
status: "hey @#{other_user.nickname}!" status: "hey @#{other_user.nickname}!"
}) })
{:ok, activity_two, _} = CommonAPI.repeat(activity_one.id, third_user) {:ok, activity_two} = CommonAPI.repeat(activity_one.id, third_user)
{enabled_receivers, _disabled_receivers} = {enabled_receivers, _disabled_receivers} =
Notification.get_notified_from_activity(activity_two) Notification.get_notified_from_activity(activity_two)
@ -778,7 +778,7 @@ defmodule Pleroma.NotificationTest do
assert Enum.empty?(Notification.for_user(user)) assert Enum.empty?(Notification.for_user(user))
{:ok, _, _} = CommonAPI.repeat(activity.id, other_user) {:ok, _} = CommonAPI.repeat(activity.id, other_user)
assert length(Notification.for_user(user)) == 1 assert length(Notification.for_user(user)) == 1
@ -795,7 +795,7 @@ defmodule Pleroma.NotificationTest do
assert Enum.empty?(Notification.for_user(user)) assert Enum.empty?(Notification.for_user(user))
{:ok, _, _} = CommonAPI.repeat(activity.id, other_user) {:ok, _} = CommonAPI.repeat(activity.id, other_user)
assert length(Notification.for_user(user)) == 1 assert length(Notification.for_user(user)) == 1

View File

@ -91,6 +91,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do
describe "running rm" do describe "running rm" do
test "user is deleted" do test "user is deleted" do
clear_config([:instance, :federating], true)
user = insert(:user) user = insert(:user)
with_mock Pleroma.Web.Federator, with_mock Pleroma.Web.Federator,
@ -108,8 +109,10 @@ defmodule Mix.Tasks.Pleroma.UserTest do
test "a remote user's create activity is deleted when the object has been pruned" do test "a remote user's create activity is deleted when the object has been pruned" do
user = insert(:user) user = insert(:user)
{:ok, post} = CommonAPI.post(user, %{status: "uguu"}) {:ok, post} = CommonAPI.post(user, %{status: "uguu"})
clear_config([:instance, :federating], true)
object = Object.normalize(post) object = Object.normalize(post)
Object.prune(object) Object.prune(object)

View File

@ -992,7 +992,7 @@ defmodule Pleroma.UserTest do
user = insert(:user, local: true) user = insert(:user, local: true)
{:ok, activity} = CommonAPI.post(actor, %{status: "hello"}) {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
{:ok, announce, _} = CommonAPI.repeat(activity.id, user) {:ok, announce} = CommonAPI.repeat(activity.id, user)
recipients = User.get_recipients_from_activity(announce) recipients = User.get_recipients_from_activity(announce)
@ -1147,7 +1147,7 @@ defmodule Pleroma.UserTest do
{:ok, like} = CommonAPI.favorite(user, activity_two.id) {:ok, like} = CommonAPI.favorite(user, activity_two.id)
{:ok, like_two} = CommonAPI.favorite(follower, activity.id) {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
{:ok, repeat, _} = CommonAPI.repeat(activity_two.id, user) {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
{:ok, job} = User.delete(user) {:ok, job} = User.delete(user)
{:ok, _user} = ObanHelpers.perform(job) {:ok, _user} = ObanHelpers.perform(job)

View File

@ -537,7 +537,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert Enum.member?(activities, activity_one) assert Enum.member?(activities, activity_one)
{:ok, _user_relationship} = User.block(user, %{ap_id: activity_three.data["actor"]}) {:ok, _user_relationship} = User.block(user, %{ap_id: activity_three.data["actor"]})
{:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster) {:ok, %{data: %{"object" => id}}} = CommonAPI.repeat(activity_three.id, booster)
%Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id) %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
activity_three = Activity.get_by_id(activity_three.id) activity_three = Activity.get_by_id(activity_three.id)
@ -592,7 +592,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, activity_two} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"}) {:ok, activity_two} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"})
{:ok, activity_three, _} = CommonAPI.repeat(activity_two.id, friend) {:ok, activity_three} = CommonAPI.repeat(activity_two.id, friend)
activities = activities =
ActivityPub.fetch_activities([], %{"blocking_user" => blocker}) ActivityPub.fetch_activities([], %{"blocking_user" => blocker})
@ -618,7 +618,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
followed_user = insert(:user) followed_user = insert(:user)
ActivityPub.follow(user, followed_user) ActivityPub.follow(user, followed_user)
{:ok, repeat_activity, _} = CommonAPI.repeat(activity.id, followed_user) {:ok, repeat_activity} = CommonAPI.repeat(activity.id, followed_user)
activities = activities =
ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true}) ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
@ -651,7 +651,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
another_user = insert(:user, %{ap_id: "https://#{domain}/@meanie2"}) another_user = insert(:user, %{ap_id: "https://#{domain}/@meanie2"})
bad_note = insert(:note, %{data: %{"actor" => another_user.ap_id}}) bad_note = insert(:note, %{data: %{"actor" => another_user.ap_id}})
bad_activity = insert(:note_activity, %{note: bad_note}) bad_activity = insert(:note_activity, %{note: bad_note})
{:ok, repeat_activity, _} = CommonAPI.repeat(bad_activity.id, domain_user) {:ok, repeat_activity} = CommonAPI.repeat(bad_activity.id, domain_user)
activities = activities =
ActivityPub.fetch_activities([], %{"blocking_user" => blocker, "skip_preload" => true}) ActivityPub.fetch_activities([], %{"blocking_user" => blocker, "skip_preload" => true})
@ -699,7 +699,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
activity_three_actor = User.get_by_ap_id(activity_three.data["actor"]) activity_three_actor = User.get_by_ap_id(activity_three.data["actor"])
{:ok, _user_relationships} = User.mute(user, activity_three_actor) {:ok, _user_relationships} = User.mute(user, activity_three_actor)
{:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster) {:ok, %{data: %{"object" => id}}} = CommonAPI.repeat(activity_three.id, booster)
%Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id) %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
activity_three = Activity.get_by_id(activity_three.id) activity_three = Activity.get_by_id(activity_three.id)
@ -749,7 +749,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, user} = User.follow(user, booster) {:ok, user} = User.follow(user, booster)
{:ok, announce, _object} = CommonAPI.repeat(activity_three.id, booster) {:ok, announce} = CommonAPI.repeat(activity_three.id, booster)
[announce_activity] = ActivityPub.fetch_activities([user.ap_id | User.following(user)]) [announce_activity] = ActivityPub.fetch_activities([user.ap_id | User.following(user)])
@ -846,7 +846,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
booster = insert(:user) booster = insert(:user)
{:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, booster) {:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, booster)
{:ok, activity, _} = CommonAPI.repeat(activity.id, booster) {:ok, activity} = CommonAPI.repeat(activity.id, booster)
activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
@ -860,7 +860,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, booster) {:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, booster)
{:ok, _reblog_mute} = CommonAPI.show_reblogs(user, booster) {:ok, _reblog_mute} = CommonAPI.show_reblogs(user, booster)
{:ok, activity, _} = CommonAPI.repeat(activity.id, booster) {:ok, activity} = CommonAPI.repeat(activity.id, booster)
activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
@ -868,75 +868,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
end end
end end
describe "announcing an object" do
test "adds an announce activity to the db" do
note_activity = insert(:note_activity)
object = Object.normalize(note_activity)
user = insert(:user)
{:ok, announce_activity, object} = ActivityPub.announce(user, object)
assert object.data["announcement_count"] == 1
assert object.data["announcements"] == [user.ap_id]
assert announce_activity.data["to"] == [
User.ap_followers(user),
note_activity.data["actor"]
]
assert announce_activity.data["object"] == object.data["id"]
assert announce_activity.data["actor"] == user.ap_id
assert announce_activity.data["context"] == object.data["context"]
end
test "reverts annouce from object on error" do
note_activity = insert(:note_activity)
object = Object.normalize(note_activity)
user = insert(:user)
with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
assert {:error, :reverted} = ActivityPub.announce(user, object)
end
reloaded_object = Object.get_by_ap_id(object.data["id"])
assert reloaded_object == object
refute reloaded_object.data["announcement_count"]
refute reloaded_object.data["announcements"]
end
end
describe "announcing a private object" do
test "adds an announce activity to the db if the audience is not widened" do
user = insert(:user)
{:ok, note_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"})
object = Object.normalize(note_activity)
{:ok, announce_activity, object} = ActivityPub.announce(user, object, nil, true, false)
assert announce_activity.data["to"] == [User.ap_followers(user)]
assert announce_activity.data["object"] == object.data["id"]
assert announce_activity.data["actor"] == user.ap_id
assert announce_activity.data["context"] == object.data["context"]
end
test "does not add an announce activity to the db if the audience is widened" do
user = insert(:user)
{:ok, note_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"})
object = Object.normalize(note_activity)
assert {:error, _} = ActivityPub.announce(user, object, nil, true, true)
end
test "does not add an announce activity to the db if the announcer is not the author" do
user = insert(:user)
announcer = insert(:user)
{:ok, note_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"})
object = Object.normalize(note_activity)
assert {:error, _} = ActivityPub.announce(announcer, object, nil, true, false)
end
end
describe "uploading files" do describe "uploading files" do
test "copies the file to the configured folder" do test "copies the file to the configured folder" do
file = %Plug.Upload{ file = %Plug.Upload{

View File

@ -280,4 +280,96 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
assert {:object, valid_like["object"]} in validated.changes assert {:object, valid_like["object"]} in validated.changes
end end
end end
describe "announces" do
setup do
user = insert(:user)
announcer = insert(:user)
{:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"})
object = Object.normalize(post_activity, false)
{:ok, valid_announce, []} = Builder.announce(announcer, object)
%{
valid_announce: valid_announce,
user: user,
post_activity: post_activity,
announcer: announcer
}
end
test "returns ok for a valid announce", %{valid_announce: valid_announce} do
assert {:ok, _object, _meta} = ObjectValidator.validate(valid_announce, [])
end
test "returns an error if the object can't be found", %{valid_announce: valid_announce} do
without_object =
valid_announce
|> Map.delete("object")
{:error, cng} = ObjectValidator.validate(without_object, [])
assert {:object, {"can't be blank", [validation: :required]}} in cng.errors
nonexisting_object =
valid_announce
|> Map.put("object", "https://gensokyo.2hu/objects/99999999")
{:error, cng} = ObjectValidator.validate(nonexisting_object, [])
assert {:object, {"can't find object", []}} in cng.errors
end
test "returns an error if we don't have the actor", %{valid_announce: valid_announce} do
nonexisting_actor =
valid_announce
|> Map.put("actor", "https://gensokyo.2hu/users/raymoo")
{:error, cng} = ObjectValidator.validate(nonexisting_actor, [])
assert {:actor, {"can't find user", []}} in cng.errors
end
test "returns an error if the actor already announced the object", %{
valid_announce: valid_announce,
announcer: announcer,
post_activity: post_activity
} do
_announce = CommonAPI.repeat(post_activity.id, announcer)
{:error, cng} = ObjectValidator.validate(valid_announce, [])
assert {:actor, {"already announced this object", []}} in cng.errors
assert {:object, {"already announced by this actor", []}} in cng.errors
end
test "returns an error if the actor can't announce the object", %{
announcer: announcer,
user: user
} do
{:ok, post_activity} =
CommonAPI.post(user, %{status: "a secret post", visibility: "private"})
object = Object.normalize(post_activity, false)
# Another user can't announce it
{:ok, announce, []} = Builder.announce(announcer, object, public: false)
{:error, cng} = ObjectValidator.validate(announce, [])
assert {:actor, {"can not announce this object", []}} in cng.errors
# The actor of the object can announce it
{:ok, announce, []} = Builder.announce(user, object, public: false)
assert {:ok, _, _} = ObjectValidator.validate(announce, [])
# The actor of the object can not announce it publicly
{:ok, announce, []} = Builder.announce(user, object, public: true)
{:error, cng} = ObjectValidator.validate(announce, [])
assert {:actor, {"can not announce this object publicly", []}} in cng.errors
end
end
end end

View File

@ -9,6 +9,11 @@ defmodule Pleroma.Web.ActivityPub.PipelineTest do
import Pleroma.Factory import Pleroma.Factory
describe "common_pipeline/2" do describe "common_pipeline/2" do
setup do
clear_config([:instance, :federating], true)
:ok
end
test "it goes through validation, filtering, persisting, side effects and federation for local activities" do test "it goes through validation, filtering, persisting, side effects and federation for local activities" do
activity = insert(:note_activity) activity = insert(:note_activity)
meta = [local: true] meta = [local: true]
@ -83,5 +88,44 @@ defmodule Pleroma.Web.ActivityPub.PipelineTest do
assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta)) assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
end end
end end
test "it goes through validation, filtering, persisting, side effects without federation for local activities if federation is deactivated" do
clear_config([:instance, :federating], false)
activity = insert(:note_activity)
meta = [local: true]
with_mocks([
{Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]},
{
Pleroma.Web.ActivityPub.MRF,
[],
[filter: fn o -> {:ok, o} end]
},
{
Pleroma.Web.ActivityPub.ActivityPub,
[],
[persist: fn o, m -> {:ok, o, m} end]
},
{
Pleroma.Web.ActivityPub.SideEffects,
[],
[handle: fn o, m -> {:ok, o, m} end]
},
{
Pleroma.Web.Federator,
[],
[]
}
]) do
assert {:ok, ^activity, ^meta} =
Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta)
assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta))
assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity))
assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta))
assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
end
end
end end
end end

View File

@ -6,7 +6,6 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do
use Pleroma.DataCase use Pleroma.DataCase
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Relay
@ -95,21 +94,20 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do
end) end)
assert capture_log(fn -> assert capture_log(fn ->
assert Relay.publish(activity) == {:error, nil} assert Relay.publish(activity) == {:error, false}
end) =~ "[error] error: nil" end) =~ "[error] error: false"
end end
test_with_mock "returns announce activity and publish to federate", test_with_mock "returns announce activity and publish to federate",
Pleroma.Web.Federator, Pleroma.Web.Federator,
[:passthrough], [:passthrough],
[] do [] do
Pleroma.Config.put([:instance, :federating], true) clear_config([:instance, :federating], true)
service_actor = Relay.get_actor() service_actor = Relay.get_actor()
note = insert(:note_activity) note = insert(:note_activity)
assert {:ok, %Activity{} = activity, %Object{} = obj} = Relay.publish(note) assert {:ok, %Activity{} = activity} = Relay.publish(note)
assert activity.data["type"] == "Announce" assert activity.data["type"] == "Announce"
assert activity.data["actor"] == service_actor.ap_id assert activity.data["actor"] == service_actor.ap_id
assert activity.data["object"] == obj.data["id"]
assert called(Pleroma.Web.Federator.publish(activity)) assert called(Pleroma.Web.Federator.publish(activity))
end end
@ -117,13 +115,12 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do
Pleroma.Web.Federator, Pleroma.Web.Federator,
[:passthrough], [:passthrough],
[] do [] do
Pleroma.Config.put([:instance, :federating], false) clear_config([:instance, :federating], false)
service_actor = Relay.get_actor() service_actor = Relay.get_actor()
note = insert(:note_activity) note = insert(:note_activity)
assert {:ok, %Activity{} = activity, %Object{} = obj} = Relay.publish(note) assert {:ok, %Activity{} = activity} = Relay.publish(note)
assert activity.data["type"] == "Announce" assert activity.data["type"] == "Announce"
assert activity.data["actor"] == service_actor.ap_id assert activity.data["actor"] == service_actor.ap_id
assert activity.data["object"] == obj.data["id"]
refute called(Pleroma.Web.Federator.publish(activity)) refute called(Pleroma.Web.Federator.publish(activity))
end end
end end

View File

@ -172,7 +172,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
{:ok, post} = CommonAPI.post(poster, %{status: "hey"}) {:ok, post} = CommonAPI.post(poster, %{status: "hey"})
{:ok, like} = CommonAPI.favorite(user, post.id) {:ok, like} = CommonAPI.favorite(user, post.id)
{:ok, reaction} = CommonAPI.react_with_emoji(post.id, user, "👍") {:ok, reaction} = CommonAPI.react_with_emoji(post.id, user, "👍")
{:ok, announce, _} = CommonAPI.repeat(post.id, user) {:ok, announce} = CommonAPI.repeat(post.id, user)
{:ok, block} = ActivityPub.block(user, poster) {:ok, block} = ActivityPub.block(user, poster)
User.block(user, poster) User.block(user, poster)
@ -289,4 +289,61 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
assert Repo.get_by(Notification, user_id: poster.id, activity_id: like.id) assert Repo.get_by(Notification, user_id: poster.id, activity_id: like.id)
end end
end end
describe "announce objects" do
setup do
poster = insert(:user)
user = insert(:user)
{:ok, post} = CommonAPI.post(poster, %{status: "hey"})
{:ok, private_post} = CommonAPI.post(poster, %{status: "hey", visibility: "private"})
{:ok, announce_data, _meta} = Builder.announce(user, post.object, public: true)
{:ok, private_announce_data, _meta} =
Builder.announce(user, private_post.object, public: false)
{:ok, relay_announce_data, _meta} =
Builder.announce(Pleroma.Web.ActivityPub.Relay.get_actor(), post.object, public: true)
{:ok, announce, _meta} = ActivityPub.persist(announce_data, local: true)
{:ok, private_announce, _meta} = ActivityPub.persist(private_announce_data, local: true)
{:ok, relay_announce, _meta} = ActivityPub.persist(relay_announce_data, local: true)
%{
announce: announce,
user: user,
poster: poster,
private_announce: private_announce,
relay_announce: relay_announce
}
end
test "adds the announce to the original object", %{announce: announce, user: user} do
{:ok, announce, _} = SideEffects.handle(announce)
object = Object.get_by_ap_id(announce.data["object"])
assert object.data["announcement_count"] == 1
assert user.ap_id in object.data["announcements"]
end
test "does not add the announce to the original object if the actor is a service actor", %{
relay_announce: announce
} do
{:ok, announce, _} = SideEffects.handle(announce)
object = Object.get_by_ap_id(announce.data["object"])
assert object.data["announcement_count"] == nil
end
test "creates a notification", %{announce: announce, poster: poster} do
{:ok, announce, _} = SideEffects.handle(announce)
assert Repo.get_by(Notification, user_id: poster.id, activity_id: announce.id)
end
test "it streams out the announce", %{announce: announce} do
with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough], stream_out: fn _ -> nil end do
{:ok, announce, _} = SideEffects.handle(announce)
assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(announce))
end
end
end
end end

View File

@ -0,0 +1,172 @@
# 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.Transmogrifier.AnnounceHandlingTest do
use Pleroma.DataCase
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
test "it works for incoming honk announces" do
user = insert(:user, ap_id: "https://honktest/u/test", local: false)
other_user = insert(:user)
{:ok, post} = CommonAPI.post(other_user, %{status: "bonkeronk"})
announce = %{
"@context" => "https://www.w3.org/ns/activitystreams",
"actor" => "https://honktest/u/test",
"id" => "https://honktest/u/test/bonk/1793M7B9MQ48847vdx",
"object" => post.data["object"],
"published" => "2019-06-25T19:33:58Z",
"to" => "https://www.w3.org/ns/activitystreams#Public",
"type" => "Announce"
}
{:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(announce)
object = Object.get_by_ap_id(post.data["object"])
assert length(object.data["announcements"]) == 1
assert user.ap_id in object.data["announcements"]
end
test "it works for incoming announces with actor being inlined (kroeg)" do
data = File.read!("test/fixtures/kroeg-announce-with-inline-actor.json") |> Poison.decode!()
_user = insert(:user, local: false, ap_id: data["actor"]["id"])
other_user = insert(:user)
{:ok, post} = CommonAPI.post(other_user, %{status: "kroegeroeg"})
data =
data
|> put_in(["object", "id"], post.data["object"])
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["actor"] == "https://puckipedia.com/"
end
test "it works for incoming announces, fetching the announced object" do
data =
File.read!("test/fixtures/mastodon-announce.json")
|> Poison.decode!()
|> Map.put("object", "http://mastodon.example.org/users/admin/statuses/99541947525187367")
Tesla.Mock.mock(fn
%{method: :get} ->
%Tesla.Env{status: 200, body: File.read!("test/fixtures/mastodon-note-object.json")}
end)
_user = insert(:user, local: false, ap_id: data["actor"])
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["actor"] == "http://mastodon.example.org/users/admin"
assert data["type"] == "Announce"
assert data["id"] ==
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
assert data["object"] ==
"http://mastodon.example.org/users/admin/statuses/99541947525187367"
assert(Activity.get_create_by_object_ap_id(data["object"]))
end
@tag capture_log: true
test "it works for incoming announces with an existing activity" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
data =
File.read!("test/fixtures/mastodon-announce.json")
|> Poison.decode!()
|> Map.put("object", activity.data["object"])
_user = insert(:user, local: false, ap_id: data["actor"])
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["actor"] == "http://mastodon.example.org/users/admin"
assert data["type"] == "Announce"
assert data["id"] ==
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
assert data["object"] == activity.data["object"]
assert Activity.get_create_by_object_ap_id(data["object"]).id == activity.id
end
# Ignore inlined activities for now
@tag skip: true
test "it works for incoming announces with an inlined activity" do
data =
File.read!("test/fixtures/mastodon-announce-private.json")
|> Poison.decode!()
_user =
insert(:user,
local: false,
ap_id: data["actor"],
follower_address: data["actor"] <> "/followers"
)
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["actor"] == "http://mastodon.example.org/users/admin"
assert data["type"] == "Announce"
assert data["id"] ==
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
object = Object.normalize(data["object"])
assert object.data["id"] == "http://mastodon.example.org/@admin/99541947525187368"
assert object.data["content"] == "this is a private toot"
end
@tag capture_log: true
test "it rejects incoming announces with an inlined activity from another origin" do
Tesla.Mock.mock(fn
%{method: :get} -> %Tesla.Env{status: 404, body: ""}
end)
data =
File.read!("test/fixtures/bogus-mastodon-announce.json")
|> Poison.decode!()
_user = insert(:user, local: false, ap_id: data["actor"])
assert {:error, e} = Transmogrifier.handle_incoming(data)
end
test "it does not clobber the addressing on announce activities" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
data =
File.read!("test/fixtures/mastodon-announce.json")
|> Poison.decode!()
|> Map.put("object", Object.normalize(activity).data["id"])
|> Map.put("to", ["http://mastodon.example.org/users/admin/followers"])
|> Map.put("cc", [])
_user =
insert(:user,
local: false,
ap_id: data["actor"],
follower_address: "http://mastodon.example.org/users/admin/followers"
)
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["to"] == ["http://mastodon.example.org/users/admin/followers"]
end
end

View File

@ -28,6 +28,63 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
setup do: clear_config([:instance, :max_remote_account_fields]) setup do: clear_config([:instance, :max_remote_account_fields])
describe "handle_incoming" do describe "handle_incoming" do
test "it works for incoming notices with tag not being an array (kroeg)" do
data = File.read!("test/fixtures/kroeg-array-less-emoji.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
object = Object.normalize(data["object"])
assert object.data["emoji"] == %{
"icon_e_smile" => "https://puckipedia.com/forum/images/smilies/icon_e_smile.png"
}
data = File.read!("test/fixtures/kroeg-array-less-hashtag.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
object = Object.normalize(data["object"])
assert "test" in object.data["tag"]
end
test "it works for incoming notices with url not being a string (prismo)" do
data = File.read!("test/fixtures/prismo-url-map.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
object = Object.normalize(data["object"])
assert object.data["url"] == "https://prismo.news/posts/83"
end
test "it cleans up incoming notices which are not really DMs" do
user = insert(:user)
other_user = insert(:user)
to = [user.ap_id, other_user.ap_id]
data =
File.read!("test/fixtures/mastodon-post-activity.json")
|> Poison.decode!()
|> Map.put("to", to)
|> Map.put("cc", [])
object =
data["object"]
|> Map.put("to", to)
|> Map.put("cc", [])
data = Map.put(data, "object", object)
{:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data)
assert data["to"] == []
assert data["cc"] == to
object_data = Object.normalize(activity).data
assert object_data["to"] == []
assert object_data["cc"] == to
end
test "it ignores an incoming notice if we already have it" do test "it ignores an incoming notice if we already have it" do
activity = insert(:note_activity) activity = insert(:note_activity)
@ -260,172 +317,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
"<p>henlo from my Psion netBook</p><p>message sent from my Psion netBook</p>" "<p>henlo from my Psion netBook</p><p>message sent from my Psion netBook</p>"
end end
test "it works for incoming honk announces" do
_user = insert(:user, ap_id: "https://honktest/u/test", local: false)
other_user = insert(:user)
{:ok, post} = CommonAPI.post(other_user, %{status: "bonkeronk"})
announce = %{
"@context" => "https://www.w3.org/ns/activitystreams",
"actor" => "https://honktest/u/test",
"id" => "https://honktest/u/test/bonk/1793M7B9MQ48847vdx",
"object" => post.data["object"],
"published" => "2019-06-25T19:33:58Z",
"to" => "https://www.w3.org/ns/activitystreams#Public",
"type" => "Announce"
}
{:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(announce)
end
test "it works for incoming announces with actor being inlined (kroeg)" do
data = File.read!("test/fixtures/kroeg-announce-with-inline-actor.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["actor"] == "https://puckipedia.com/"
end
test "it works for incoming notices with tag not being an array (kroeg)" do
data = File.read!("test/fixtures/kroeg-array-less-emoji.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
object = Object.normalize(data["object"])
assert object.data["emoji"] == %{
"icon_e_smile" => "https://puckipedia.com/forum/images/smilies/icon_e_smile.png"
}
data = File.read!("test/fixtures/kroeg-array-less-hashtag.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
object = Object.normalize(data["object"])
assert "test" in object.data["tag"]
end
test "it works for incoming notices with url not being a string (prismo)" do
data = File.read!("test/fixtures/prismo-url-map.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
object = Object.normalize(data["object"])
assert object.data["url"] == "https://prismo.news/posts/83"
end
test "it cleans up incoming notices which are not really DMs" do
user = insert(:user)
other_user = insert(:user)
to = [user.ap_id, other_user.ap_id]
data =
File.read!("test/fixtures/mastodon-post-activity.json")
|> Poison.decode!()
|> Map.put("to", to)
|> Map.put("cc", [])
object =
data["object"]
|> Map.put("to", to)
|> Map.put("cc", [])
data = Map.put(data, "object", object)
{:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data)
assert data["to"] == []
assert data["cc"] == to
object_data = Object.normalize(activity).data
assert object_data["to"] == []
assert object_data["cc"] == to
end
test "it works for incoming announces" do
data = File.read!("test/fixtures/mastodon-announce.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["actor"] == "http://mastodon.example.org/users/admin"
assert data["type"] == "Announce"
assert data["id"] ==
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
assert data["object"] ==
"http://mastodon.example.org/users/admin/statuses/99541947525187367"
assert Activity.get_create_by_object_ap_id(data["object"])
end
test "it works for incoming announces with an existing activity" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
data =
File.read!("test/fixtures/mastodon-announce.json")
|> Poison.decode!()
|> Map.put("object", activity.data["object"])
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["actor"] == "http://mastodon.example.org/users/admin"
assert data["type"] == "Announce"
assert data["id"] ==
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
assert data["object"] == activity.data["object"]
assert Activity.get_create_by_object_ap_id(data["object"]).id == activity.id
end
test "it works for incoming announces with an inlined activity" do
data =
File.read!("test/fixtures/mastodon-announce-private.json")
|> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["actor"] == "http://mastodon.example.org/users/admin"
assert data["type"] == "Announce"
assert data["id"] ==
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
object = Object.normalize(data["object"])
assert object.data["id"] == "http://mastodon.example.org/@admin/99541947525187368"
assert object.data["content"] == "this is a private toot"
end
@tag capture_log: true
test "it rejects incoming announces with an inlined activity from another origin" do
data =
File.read!("test/fixtures/bogus-mastodon-announce.json")
|> Poison.decode!()
assert :error = Transmogrifier.handle_incoming(data)
end
test "it does not clobber the addressing on announce activities" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
data =
File.read!("test/fixtures/mastodon-announce.json")
|> Poison.decode!()
|> Map.put("object", Object.normalize(activity).data["id"])
|> Map.put("to", ["http://mastodon.example.org/users/admin/followers"])
|> Map.put("cc", [])
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["to"] == ["http://mastodon.example.org/users/admin/followers"]
end
test "it ensures that as:Public activities make it to their followers collection" do test "it ensures that as:Public activities make it to their followers collection" do
user = insert(:user) user = insert(:user)
@ -1188,7 +1079,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
{:ok, activity} = CommonAPI.post(user, %{status: "hey", visibility: "private"}) {:ok, activity} = CommonAPI.post(user, %{status: "hey", visibility: "private"})
{:ok, announce_activity, _} = CommonAPI.repeat(activity.id, user) {:ok, announce_activity} = CommonAPI.repeat(activity.id, user)
{:ok, modified} = Transmogrifier.prepare_outgoing(announce_activity.data) {:ok, modified} = Transmogrifier.prepare_outgoing(announce_activity.data)
@ -1438,7 +1329,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
} }
assert capture_log(fn -> assert capture_log(fn ->
:error = Transmogrifier.handle_incoming(data) {:error, _} = Transmogrifier.handle_incoming(data)
end) =~ "Object containment failed" end) =~ "Object containment failed"
end end
@ -1453,7 +1344,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
} }
assert capture_log(fn -> assert capture_log(fn ->
:error = Transmogrifier.handle_incoming(data) {:error, _} = Transmogrifier.handle_incoming(data)
end) =~ "Object containment failed" end) =~ "Object containment failed"
end end
@ -1468,7 +1359,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
} }
assert capture_log(fn -> assert capture_log(fn ->
:error = Transmogrifier.handle_incoming(data) {:error, _} = Transmogrifier.handle_incoming(data)
end) =~ "Object containment failed" end) =~ "Object containment failed"
end end
end end

View File

@ -334,7 +334,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
assert object = Object.normalize(note_activity) assert object = Object.normalize(note_activity)
actor = insert(:user) actor = insert(:user)
{:ok, announce, _object} = ActivityPub.announce(actor, object) {:ok, announce} = CommonAPI.repeat(note_activity.id, actor)
assert Utils.get_existing_announce(actor.ap_id, object) == announce assert Utils.get_existing_announce(actor.ap_id, object) == announce
end end
end end

View File

@ -73,7 +73,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectViewTest do
object = Object.normalize(note) object = Object.normalize(note)
user = insert(:user) user = insert(:user)
{:ok, announce_activity, _} = CommonAPI.repeat(note.id, user) {:ok, announce_activity} = CommonAPI.repeat(note.id, user)
result = ObjectView.render("object.json", %{object: announce_activity}) result = ObjectView.render("object.json", %{object: announce_activity})

View File

@ -148,6 +148,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
describe "DELETE /api/pleroma/admin/users" do describe "DELETE /api/pleroma/admin/users" do
test "single user", %{admin: admin, conn: conn} do test "single user", %{admin: admin, conn: conn} do
user = insert(:user) user = insert(:user)
clear_config([:instance, :federating], true)
with_mock Pleroma.Web.Federator, with_mock Pleroma.Web.Federator,
publish: fn _ -> nil end do publish: fn _ -> nil end do
@ -2944,6 +2945,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
assert ":proxy_url" in db assert ":proxy_url" in db
end end
@tag capture_log: true
test "doesn't set keys not in the whitelist", %{conn: conn} do test "doesn't set keys not in the whitelist", %{conn: conn} do
clear_config(:database_config_whitelist, [ clear_config(:database_config_whitelist, [
{:pleroma, :key1}, {:pleroma, :key1},
@ -3096,7 +3098,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
test "excludes reblogs by default", %{conn: conn, user: user} do test "excludes reblogs by default", %{conn: conn, user: user} do
other_user = insert(:user) other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "."}) {:ok, activity} = CommonAPI.post(user, %{status: "."})
{:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, other_user) {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses") conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
assert json_response(conn_res, 200) |> length() == 0 assert json_response(conn_res, 200) |> length() == 0

View File

@ -41,6 +41,8 @@ defmodule Pleroma.Web.CommonAPITest do
{:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"}) {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
clear_config([:instance, :federating], true)
Object.normalize(post, false) Object.normalize(post, false)
|> Object.prune() |> Object.prune()
@ -59,6 +61,8 @@ defmodule Pleroma.Web.CommonAPITest do
{:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"}) {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
clear_config([:instance, :federating], true)
with_mock Pleroma.Web.Federator, with_mock Pleroma.Web.Federator,
publish: fn _ -> nil end do publish: fn _ -> nil end do
assert {:ok, delete} = CommonAPI.delete(post.id, user) assert {:ok, delete} = CommonAPI.delete(post.id, user)
@ -442,7 +446,8 @@ defmodule Pleroma.Web.CommonAPITest do
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"}) {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
{:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, user) {:ok, %Activity{} = announce_activity} = CommonAPI.repeat(activity.id, user)
assert Visibility.is_public?(announce_activity)
end end
test "can't repeat a repeat" do test "can't repeat a repeat" do
@ -450,9 +455,9 @@ defmodule Pleroma.Web.CommonAPITest do
other_user = insert(:user) other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"}) {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
{:ok, %Activity{} = announce, _} = CommonAPI.repeat(activity.id, other_user) {:ok, %Activity{} = announce} = CommonAPI.repeat(activity.id, other_user)
refute match?({:ok, %Activity{}, _}, CommonAPI.repeat(announce.id, user)) refute match?({:ok, %Activity{}}, CommonAPI.repeat(announce.id, user))
end end
test "repeating a status privately" do test "repeating a status privately" do
@ -461,10 +466,11 @@ defmodule Pleroma.Web.CommonAPITest do
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"}) {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
{:ok, %Activity{} = announce_activity, _} = {:ok, %Activity{} = announce_activity} =
CommonAPI.repeat(activity.id, user, %{visibility: "private"}) CommonAPI.repeat(activity.id, user, %{visibility: "private"})
assert Visibility.is_private?(announce_activity) assert Visibility.is_private?(announce_activity)
refute Visibility.visible_for_user?(announce_activity, nil)
end end
test "favoriting a status" do test "favoriting a status" do
@ -484,8 +490,8 @@ defmodule Pleroma.Web.CommonAPITest do
other_user = insert(:user) other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"}) {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
{:ok, %Activity{} = announce, object} = CommonAPI.repeat(activity.id, user) {:ok, %Activity{} = announce} = CommonAPI.repeat(activity.id, user)
{:ok, ^announce, ^object} = CommonAPI.repeat(activity.id, user) {:ok, ^announce} = CommonAPI.repeat(activity.id, user)
end end
test "favoriting a status twice returns ok, but without the like activity" do test "favoriting a status twice returns ok, but without the like activity" do

View File

@ -256,7 +256,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
User.block(user_one, user_two) User.block(user_one, user_two)
{:ok, activity} = CommonAPI.post(user_two, %{status: "User one sux0rz"}) {:ok, activity} = CommonAPI.post(user_two, %{status: "User one sux0rz"})
{:ok, repeat, _} = CommonAPI.repeat(activity.id, user_three) {:ok, repeat} = CommonAPI.repeat(activity.id, user_three)
assert resp = assert resp =
conn conn
@ -375,7 +375,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
test "gets a user's statuses without reblogs", %{user: user, conn: conn} do test "gets a user's statuses without reblogs", %{user: user, conn: conn} do
{:ok, %{id: post_id}} = CommonAPI.post(user, %{status: "HI!!!"}) {:ok, %{id: post_id}} = CommonAPI.post(user, %{status: "HI!!!"})
{:ok, _, _} = CommonAPI.repeat(post_id, user) {:ok, _} = CommonAPI.repeat(post_id, user)
conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=true") conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=true")
assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200) assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200)
@ -678,7 +678,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
assert %{"showing_reblogs" => false} = json_response_and_validate_schema(ret_conn, 200) assert %{"showing_reblogs" => false} = json_response_and_validate_schema(ret_conn, 200)
{:ok, activity} = CommonAPI.post(other_user, %{status: "hey"}) {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
{:ok, %{id: reblog_id}, _} = CommonAPI.repeat(activity.id, followed) {:ok, %{id: reblog_id}} = CommonAPI.repeat(activity.id, followed)
assert [] == assert [] ==
conn conn

View File

@ -280,8 +280,8 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
{:ok, unlisted_activity} = {:ok, unlisted_activity} =
CommonAPI.post(other_user, %{status: ".", visibility: "unlisted"}) CommonAPI.post(other_user, %{status: ".", visibility: "unlisted"})
{:ok, _, _} = CommonAPI.repeat(public_activity.id, user) {:ok, _} = CommonAPI.repeat(public_activity.id, user)
{:ok, _, _} = CommonAPI.repeat(unlisted_activity.id, user) {:ok, _} = CommonAPI.repeat(unlisted_activity.id, user)
activity_ids = activity_ids =
conn conn
@ -301,7 +301,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
{:ok, mention_activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"}) {:ok, mention_activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"})
{:ok, create_activity} = CommonAPI.post(user, %{status: "hey"}) {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"})
{:ok, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id) {:ok, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id)
{:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user) {:ok, reblog_activity} = CommonAPI.repeat(create_activity.id, other_user)
{:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user) {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
mention_notification_id = get_notification_id_by_activity(mention_activity) mention_notification_id = get_notification_id_by_activity(mention_activity)
@ -339,7 +339,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
{:ok, mention_activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"}) {:ok, mention_activity} = CommonAPI.post(other_user, %{status: "hey @#{user.nickname}"})
{:ok, create_activity} = CommonAPI.post(user, %{status: "hey"}) {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"})
{:ok, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id) {:ok, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id)
{:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user) {:ok, reblog_activity} = CommonAPI.repeat(create_activity.id, other_user)
{:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user) {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
mention_notification_id = get_notification_id_by_activity(mention_activity) mention_notification_id = get_notification_id_by_activity(mention_activity)

View File

@ -878,8 +878,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
user3 = insert(:user) user3 = insert(:user)
{:ok, _} = CommonAPI.favorite(user2, activity.id) {:ok, _} = CommonAPI.favorite(user2, activity.id)
{:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id) {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id)
{:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1) {:ok, reblog_activity1} = CommonAPI.repeat(activity.id, user1)
{:ok, _, _object} = CommonAPI.repeat(activity.id, user2) {:ok, _} = CommonAPI.repeat(activity.id, user2)
conn_res = conn_res =
build_conn() build_conn()
@ -917,7 +917,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
test "unreblogs and returns the unreblogged status", %{user: user, conn: conn} do test "unreblogs and returns the unreblogged status", %{user: user, conn: conn} do
activity = insert(:note_activity) activity = insert(:note_activity)
{:ok, _, _} = CommonAPI.repeat(activity.id, user) {:ok, _} = CommonAPI.repeat(activity.id, user)
conn = conn =
conn conn
@ -1427,7 +1427,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
test "returns users who have reblogged the status", %{conn: conn, activity: activity} do test "returns users who have reblogged the status", %{conn: conn, activity: activity} do
other_user = insert(:user) other_user = insert(:user)
{:ok, _, _} = CommonAPI.repeat(activity.id, other_user) {:ok, _} = CommonAPI.repeat(activity.id, other_user)
response = response =
conn conn
@ -1458,7 +1458,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
other_user = insert(:user) other_user = insert(:user)
{:ok, _user_relationship} = User.block(user, other_user) {:ok, _user_relationship} = User.block(user, other_user)
{:ok, _, _} = CommonAPI.repeat(activity.id, other_user) {:ok, _} = CommonAPI.repeat(activity.id, other_user)
response = response =
conn conn
@ -1469,12 +1469,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
end end
test "does not return users who have reblogged the status privately", %{ test "does not return users who have reblogged the status privately", %{
conn: conn, conn: conn
activity: activity
} do } do
other_user = insert(:user) other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{status: "my secret post"})
{:ok, _, _} = CommonAPI.repeat(activity.id, other_user, %{visibility: "private"}) {:ok, _} = CommonAPI.repeat(activity.id, other_user, %{visibility: "private"})
response = response =
conn conn
@ -1486,7 +1486,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
test "does not fail on an unauthenticated request", %{activity: activity} do test "does not fail on an unauthenticated request", %{activity: activity} do
other_user = insert(:user) other_user = insert(:user)
{:ok, _, _} = CommonAPI.repeat(activity.id, other_user) {:ok, _} = CommonAPI.repeat(activity.id, other_user)
response = response =
build_conn() build_conn()

View File

@ -78,7 +78,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
user = insert(:user) user = insert(:user)
another_user = insert(:user) another_user = insert(:user)
{:ok, create_activity} = CommonAPI.post(user, %{status: "hey"}) {:ok, create_activity} = CommonAPI.post(user, %{status: "hey"})
{:ok, reblog_activity, _object} = CommonAPI.repeat(create_activity.id, another_user) {:ok, reblog_activity} = CommonAPI.repeat(create_activity.id, another_user)
{:ok, [notification]} = Notification.create_notifications(reblog_activity) {:ok, [notification]} = Notification.create_notifications(reblog_activity)
reblog_activity = Activity.get_by_id(create_activity.id) reblog_activity = Activity.get_by_id(create_activity.id)

View File

@ -442,7 +442,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
user = insert(:user) user = insert(:user)
activity = insert(:note_activity) activity = insert(:note_activity)
{:ok, reblog, _} = CommonAPI.repeat(activity.id, user) {:ok, reblog} = CommonAPI.repeat(activity.id, user)
represented = StatusView.render("show.json", %{for: user, activity: reblog}) represented = StatusView.render("show.json", %{for: user, activity: reblog})
@ -600,7 +600,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
status: "˙˙ɐʎns" status: "˙˙ɐʎns"
}) })
{:ok, activity, _object} = CommonAPI.repeat(activity.id, other_user) {:ok, activity} = CommonAPI.repeat(activity.id, other_user)
result = StatusView.render("show.json", %{activity: activity, for: user}) result = StatusView.render("show.json", %{activity: activity, for: user})

View File

@ -151,7 +151,7 @@ defmodule Pleroma.Web.Push.ImplTest do
"<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis." "<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis."
}) })
{:ok, announce_activity, _} = CommonAPI.repeat(activity.id, user) {:ok, announce_activity} = CommonAPI.repeat(activity.id, user)
object = Object.normalize(activity) object = Object.normalize(activity)
assert Impl.format_body(%{activity: announce_activity}, user, object) == assert Impl.format_body(%{activity: announce_activity}, user, object) ==

View File

@ -106,7 +106,7 @@ defmodule Pleroma.Web.StreamerTest do
other_user = insert(:user) other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{status: "hey"}) {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
{:ok, announce, _} = CommonAPI.repeat(activity.id, user) {:ok, announce} = CommonAPI.repeat(activity.id, user)
assert_receive {:render_with_user, Pleroma.Web.StreamerView, "update.json", ^announce} assert_receive {:render_with_user, Pleroma.Web.StreamerView, "update.json", ^announce}
refute Streamer.filtered_by_user?(user, announce) refute Streamer.filtered_by_user?(user, announce)
@ -427,7 +427,7 @@ defmodule Pleroma.Web.StreamerTest do
{:ok, create_activity} = CommonAPI.post(user3, %{status: "I'm kawen"}) {:ok, create_activity} = CommonAPI.post(user3, %{status: "I'm kawen"})
Streamer.get_topic_and_add_socket("user", user1) Streamer.get_topic_and_add_socket("user", user1)
{:ok, announce_activity, _} = CommonAPI.repeat(create_activity.id, user2) {:ok, announce_activity} = CommonAPI.repeat(create_activity.id, user2)
assert_receive {:render_with_user, _, _, ^announce_activity} assert_receive {:render_with_user, _, _, ^announce_activity}
assert Streamer.filtered_by_user?(user1, announce_activity) assert Streamer.filtered_by_user?(user1, announce_activity)
end end
@ -440,7 +440,7 @@ defmodule Pleroma.Web.StreamerTest do
{:ok, create_activity} = CommonAPI.post(user1, %{status: "I'm kawen"}) {:ok, create_activity} = CommonAPI.post(user1, %{status: "I'm kawen"})
Streamer.get_topic_and_add_socket("user", user1) Streamer.get_topic_and_add_socket("user", user1)
{:ok, _favorite_activity, _} = CommonAPI.repeat(create_activity.id, user2) {:ok, _announce_activity} = CommonAPI.repeat(create_activity.id, user2)
assert_receive {:render_with_user, _, "notification.json", notif} assert_receive {:render_with_user, _, "notification.json", notif}
assert Streamer.filtered_by_user?(user1, notif) assert Streamer.filtered_by_user?(user1, notif)