summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--docs/API/differences_in_mastoapi_responses.md8
-rw-r--r--lib/pleroma/activity.ex3
-rw-r--r--lib/pleroma/following_relationship.ex18
-rw-r--r--lib/pleroma/notification.ex33
-rw-r--r--lib/pleroma/user.ex13
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex27
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex20
-rw-r--r--lib/pleroma/web/activity_pub/visibility.ex1
-rw-r--r--lib/pleroma/web/common_api/utils.ex13
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/account_controller.ex1
-rw-r--r--lib/pleroma/web/mastodon_api/views/account_view.ex7
-rw-r--r--lib/pleroma/web/mastodon_api/views/notification_view.ex38
-rw-r--r--lib/pleroma/web/push/impl.ex2
-rw-r--r--lib/pleroma/workers/background_worker.ex7
-rw-r--r--priv/repo/migrations/20191025081729_add_move_support_to_users.exs10
-rw-r--r--priv/static/schemas/litepub-0.1.jsonld6
-rw-r--r--test/fixtures/tesla_mock/admin@mastdon.example.org.json9
-rw-r--r--test/notification_test.exs29
-rw-r--r--test/web/activity_pub/activity_pub_test.exs63
-rw-r--r--test/web/activity_pub/transmogrifier_test.exs55
-rw-r--r--test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs15
-rw-r--r--test/web/mastodon_api/views/account_view_test.exs2
-rw-r--r--test/web/mastodon_api/views/notification_view_test.exs24
24 files changed, 354 insertions, 51 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e44c892ab..a06ea211e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -66,6 +66,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- `DELETE /api/pleroma/admin/users` (`nickname` query param or `nickname` sent in JSON body) is deprecated in favor of: `DELETE /api/pleroma/admin/users` (`nicknames` query array param or `nicknames` sent in JSON body)
- Admin API: Add `GET /api/pleroma/admin/relay` endpoint - lists all followed relays
- Pleroma API: `POST /api/v1/pleroma/conversations/read` to mark all conversations as read
+- ActivityPub: Support `Move` activities
- Mastodon API: Add `/api/v1/markers` for managing timeline read markers
- Mastodon API: Add the `recipients` parameter to `GET /api/v1/conversations`
- Configuration: `feed` option for user atom feed.
diff --git a/docs/API/differences_in_mastoapi_responses.md b/docs/API/differences_in_mastoapi_responses.md
index 7fbe17130..006d17c1b 100644
--- a/docs/API/differences_in_mastoapi_responses.md
+++ b/docs/API/differences_in_mastoapi_responses.md
@@ -57,6 +57,7 @@ Has these additional fields under the `pleroma` object:
- `settings_store`: A generic map of settings for frontends. Opaque to the backend. Only returned in `verify_credentials` and `update_credentials`
- `chat_token`: The token needed for Pleroma chat. Only returned in `verify_credentials`
- `deactivated`: boolean, true when the user is deactivated
+- `allow_following_move`: boolean, true when the user allows automatically follow moved following accounts
- `unread_conversation_count`: The count of unread conversations. Only returned to the account owner.
### Source
@@ -91,6 +92,12 @@ Has these additional fields under the `pleroma` object:
- `is_seen`: true if the notification was read by the user
+### Move Notification
+
+The `type` value is `move`. Has an additional field:
+
+- `target`: new account
+
## GET `/api/v1/notifications`
Accepts additional parameters:
@@ -136,6 +143,7 @@ Additional parameters can be added to the JSON body/Form data:
- `default_scope` - the scope returned under `privacy` key in Source subentity
- `pleroma_settings_store` - Opaque user settings to be saved on the backend.
- `skip_thread_containment` - if true, skip filtering out broken threads
+- `allow_following_move` - if true, allows automatically follow moved following accounts
- `pleroma_background_image` - sets the background image of the user.
### Pleroma Settings Store
diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex
index cd7a5aae9..f180c1e33 100644
--- a/lib/pleroma/activity.ex
+++ b/lib/pleroma/activity.ex
@@ -28,7 +28,8 @@ defmodule Pleroma.Activity do
"Create" => "mention",
"Follow" => "follow",
"Announce" => "reblog",
- "Like" => "favourite"
+ "Like" => "favourite",
+ "Move" => "move"
}
@mastodon_to_ap_notification_types for {k, v} <- @mastodon_notification_types,
diff --git a/lib/pleroma/following_relationship.ex b/lib/pleroma/following_relationship.ex
index 3aff9fb76..a03c9bd30 100644
--- a/lib/pleroma/following_relationship.ex
+++ b/lib/pleroma/following_relationship.ex
@@ -107,4 +107,22 @@ defmodule Pleroma.FollowingRelationship do
[user.follower_address | following]
end
end
+
+ def move_following(origin, target) do
+ __MODULE__
+ |> join(:inner, [r], f in assoc(r, :follower))
+ |> where(following_id: ^origin.id)
+ |> where([r, f], f.allow_following_move == true)
+ |> limit(50)
+ |> preload([:follower])
+ |> Repo.all()
+ |> Enum.map(fn following_relationship ->
+ Repo.delete(following_relationship)
+ Pleroma.Web.CommonAPI.follow(following_relationship.follower, target)
+ end)
+ |> case do
+ [] -> :ok
+ _ -> move_following(origin, target)
+ end
+ end
end
diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex
index b7ecf51e4..f37e7ec67 100644
--- a/lib/pleroma/notification.ex
+++ b/lib/pleroma/notification.ex
@@ -251,10 +251,13 @@ defmodule Pleroma.Notification do
end
end
- def create_notifications(%Activity{data: %{"to" => _, "type" => type}} = activity)
- when type in ["Like", "Announce", "Follow"] do
- users = get_notified_from_activity(activity)
- notifications = Enum.map(users, fn user -> create_notification(activity, user) end)
+ def create_notifications(%Activity{data: %{"type" => type}} = activity)
+ when type in ["Like", "Announce", "Follow", "Move"] do
+ notifications =
+ activity
+ |> get_notified_from_activity()
+ |> Enum.map(&create_notification(activity, &1))
+
{:ok, notifications}
end
@@ -276,19 +279,15 @@ defmodule Pleroma.Notification do
def get_notified_from_activity(activity, local_only \\ true)
- def get_notified_from_activity(
- %Activity{data: %{"to" => _, "type" => type} = _data} = activity,
- local_only
- )
- when type in ["Create", "Like", "Announce", "Follow"] do
- recipients =
- []
- |> Utils.maybe_notify_to_recipients(activity)
- |> Utils.maybe_notify_mentioned_recipients(activity)
- |> Utils.maybe_notify_subscribers(activity)
- |> Enum.uniq()
-
- User.get_users_from_set(recipients, local_only)
+ def get_notified_from_activity(%Activity{data: %{"type" => type}} = activity, local_only)
+ when type in ["Create", "Like", "Announce", "Follow", "Move"] do
+ []
+ |> Utils.maybe_notify_to_recipients(activity)
+ |> Utils.maybe_notify_mentioned_recipients(activity)
+ |> Utils.maybe_notify_subscribers(activity)
+ |> Utils.maybe_notify_followers(activity)
+ |> Enum.uniq()
+ |> User.get_users_from_set(local_only)
end
def get_notified_from_activity(_, _local_only), do: []
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 8851b0a79..120cb2641 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -103,7 +103,9 @@ defmodule Pleroma.User do
field(:raw_fields, {:array, :map}, default: [])
field(:discoverable, :boolean, default: false)
field(:invisible, :boolean, default: false)
+ field(:allow_following_move, :boolean, default: true)
field(:skip_thread_containment, :boolean, default: false)
+ field(:also_known_as, {:array, :string}, default: [])
field(:notification_settings, :map,
default: %{
@@ -251,7 +253,8 @@ defmodule Pleroma.User do
:fields,
:following_count,
:discoverable,
- :invisible
+ :invisible,
+ :also_known_as
]
)
|> validate_required([:name, :ap_id])
@@ -293,13 +296,15 @@ defmodule Pleroma.User do
:hide_followers_count,
:hide_follows_count,
:hide_favorites,
+ :allow_following_move,
:background,
:show_role,
:skip_thread_containment,
:fields,
:raw_fields,
:pleroma_settings_store,
- :discoverable
+ :discoverable,
+ :also_known_as
]
)
|> unique_constraint(:nickname)
@@ -337,9 +342,11 @@ defmodule Pleroma.User do
:hide_follows,
:fields,
:hide_followers,
+ :allow_following_move,
:discoverable,
:hide_followers_count,
- :hide_follows_count
+ :hide_follows_count,
+ :also_known_as
]
)
|> unique_constraint(:nickname)
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index f32d04175..d6a425d8b 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -541,6 +541,30 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
+ def move(%User{} = origin, %User{} = target, local \\ true) do
+ params = %{
+ "type" => "Move",
+ "actor" => origin.ap_id,
+ "object" => origin.ap_id,
+ "target" => target.ap_id
+ }
+
+ with true <- origin.ap_id in target.also_known_as,
+ {:ok, activity} <- insert(params, local) do
+ maybe_federate(activity)
+
+ BackgroundWorker.enqueue("move_following", %{
+ "origin_id" => origin.id,
+ "target_id" => target.id
+ })
+
+ {:ok, activity}
+ else
+ false -> {:error, "Target account must have the origin in `alsoKnownAs`"}
+ err -> err
+ end
+ end
+
defp fetch_activities_for_context_query(context, opts) do
public = [Pleroma.Constants.as_public()]
@@ -1171,7 +1195,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
name: data["name"],
follower_address: data["followers"],
following_address: data["following"],
- bio: data["summary"]
+ bio: data["summary"],
+ also_known_as: Map.get(data, "alsoKnownAs", [])
}
# nickname can be nil because of virtual actors
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 15612545b..ce95fb6ba 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -669,7 +669,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
update_data =
new_user_data
- |> Map.take([:avatar, :banner, :bio, :name])
+ |> Map.take([:avatar, :banner, :bio, :name, :also_known_as])
|> Map.put(:fields, fields)
|> Map.put(:locked, locked)
|> Map.put(:invisible, invisible)
@@ -857,6 +857,24 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
end
+ def handle_incoming(
+ %{
+ "type" => "Move",
+ "actor" => origin_actor,
+ "object" => origin_actor,
+ "target" => target_actor
+ },
+ _options
+ ) do
+ with %User{} = origin_user <- User.get_cached_by_ap_id(origin_actor),
+ {:ok, %User{} = target_user} <- User.get_or_fetch_by_ap_id(target_actor),
+ true <- origin_actor in target_user.also_known_as do
+ ActivityPub.move(origin_user, target_user, false)
+ else
+ _e -> :error
+ end
+ end
+
def handle_incoming(_, _), do: :error
@spec get_obj_helper(String.t(), Keyword.t()) :: {:ok, Object.t()} | nil
diff --git a/lib/pleroma/web/activity_pub/visibility.ex b/lib/pleroma/web/activity_pub/visibility.ex
index cd4097493..e172f6d3f 100644
--- a/lib/pleroma/web/activity_pub/visibility.ex
+++ b/lib/pleroma/web/activity_pub/visibility.ex
@@ -14,6 +14,7 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
@spec is_public?(Object.t() | Activity.t() | map()) :: boolean()
def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false
def is_public?(%Object{data: data}), do: is_public?(data)
+ def is_public?(%Activity{data: %{"type" => "Move"}}), do: true
def is_public?(%Activity{data: data}), do: is_public?(data)
def is_public?(%{"directMessage" => true}), do: false
def is_public?(data), do: Utils.label_in_message?(Pleroma.Constants.as_public(), data)
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index 88a5f434a..cbb64f8d2 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -451,6 +451,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do
recipients ++ to
end
+ def maybe_notify_to_recipients(recipients, _), do: recipients
+
def maybe_notify_mentioned_recipients(
recipients,
%Activity{data: %{"to" => _to, "type" => type} = data} = activity
@@ -502,6 +504,17 @@ defmodule Pleroma.Web.CommonAPI.Utils do
def maybe_notify_subscribers(recipients, _), do: recipients
+ def maybe_notify_followers(recipients, %Activity{data: %{"type" => "Move"}} = activity) do
+ with %User{} = user <- User.get_cached_by_ap_id(activity.actor) do
+ user
+ |> User.get_followers()
+ |> Enum.map(& &1.ap_id)
+ |> Enum.concat(recipients)
+ end
+ end
+
+ def maybe_notify_followers(recipients, _), do: recipients
+
def maybe_extract_mentions(%{"tag" => tag}) do
tag
|> Enum.filter(fn x -> is_map(x) && x["type"] == "Mention" end)
diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
index 5f2544640..a69423f60 100644
--- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
@@ -152,6 +152,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
:hide_favorites,
:show_role,
:skip_thread_containment,
+ :allow_following_move,
:discoverable
]
|> Enum.reduce(%{}, fn key, acc ->
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index 1068f8823..ec720e472 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -162,6 +162,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|> maybe_put_chat_token(user, opts[:for], opts)
|> maybe_put_activation_status(user, opts[:for])
|> maybe_put_follow_requests_count(user, opts[:for])
+ |> maybe_put_allow_following_move(user, opts[:for])
|> maybe_put_unread_conversation_count(user, opts[:for])
end
@@ -238,6 +239,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
defp maybe_put_notification_settings(data, _, _), do: data
+ defp maybe_put_allow_following_move(data, %User{id: user_id} = user, %User{id: user_id}) do
+ Kernel.put_in(data, [:pleroma, :allow_following_move], user.allow_following_move)
+ end
+
+ defp maybe_put_allow_following_move(data, _, _), do: data
+
defp maybe_put_activation_status(data, user, %User{is_admin: true}) do
Kernel.put_in(data, [:pleroma, :deactivated], user.deactivated)
end
diff --git a/lib/pleroma/web/mastodon_api/views/notification_view.ex b/lib/pleroma/web/mastodon_api/views/notification_view.ex
index 5e3dbe728..ddd7f5318 100644
--- a/lib/pleroma/web/mastodon_api/views/notification_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/notification_view.ex
@@ -37,32 +37,24 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
}
case mastodon_type do
- "mention" ->
- response
- |> Map.merge(%{
- status: StatusView.render("show.json", %{activity: activity, for: user})
- })
-
- "favourite" ->
- response
- |> Map.merge(%{
- status: StatusView.render("show.json", %{activity: parent_activity, for: user})
- })
-
- "reblog" ->
- response
- |> Map.merge(%{
- status: StatusView.render("show.json", %{activity: parent_activity, for: user})
- })
-
- "follow" ->
- response
-
- _ ->
- nil
+ "mention" -> put_status(response, activity, user)
+ "favourite" -> put_status(response, parent_activity, user)
+ "reblog" -> put_status(response, parent_activity, user)
+ "move" -> put_target(response, activity, user)
+ "follow" -> response
+ _ -> nil
end
else
_ -> nil
end
end
+
+ defp put_status(response, activity, user) do
+ Map.put(response, :status, StatusView.render("show.json", %{activity: activity, for: user}))
+ end
+
+ defp put_target(response, activity, user) do
+ target = User.get_cached_by_ap_id(activity.data["target"])
+ Map.put(response, :target, AccountView.render("show.json", %{user: target, for: user}))
+ end
end
diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex
index 3de7af708..a6a924d02 100644
--- a/lib/pleroma/web/push/impl.ex
+++ b/lib/pleroma/web/push/impl.ex
@@ -16,7 +16,7 @@ defmodule Pleroma.Web.Push.Impl do
require Logger
import Ecto.Query
- @types ["Create", "Follow", "Announce", "Like"]
+ @types ["Create", "Follow", "Announce", "Like", "Move"]
@doc "Performs sending notifications for user subscriptions"
@spec perform(Notification.t()) :: list(any) | :error
diff --git a/lib/pleroma/workers/background_worker.ex b/lib/pleroma/workers/background_worker.ex
index 7ffc8eabe..323a4da1e 100644
--- a/lib/pleroma/workers/background_worker.ex
+++ b/lib/pleroma/workers/background_worker.ex
@@ -71,4 +71,11 @@ defmodule Pleroma.Workers.BackgroundWorker do
activity = Activity.get_by_id(activity_id)
Pleroma.Web.RichMedia.Helpers.perform(:fetch, activity)
end
+
+ def perform(%{"op" => "move_following", "origin_id" => origin_id, "target_id" => target_id}, _) do
+ origin = User.get_cached_by_id(origin_id)
+ target = User.get_cached_by_id(target_id)
+
+ Pleroma.FollowingRelationship.move_following(origin, target)
+ end
end
diff --git a/priv/repo/migrations/20191025081729_add_move_support_to_users.exs b/priv/repo/migrations/20191025081729_add_move_support_to_users.exs
new file mode 100644
index 000000000..580b9eb0f
--- /dev/null
+++ b/priv/repo/migrations/20191025081729_add_move_support_to_users.exs
@@ -0,0 +1,10 @@
+defmodule Pleroma.Repo.Migrations.AddMoveSupportToUsers do
+ use Ecto.Migration
+
+ def change do
+ alter table(:users) do
+ add(:also_known_as, {:array, :string}, default: [], null: false)
+ add(:allow_following_move, :boolean, default: true, null: false)
+ end
+ end
+end
diff --git a/priv/static/schemas/litepub-0.1.jsonld b/priv/static/schemas/litepub-0.1.jsonld
index 8bae42f6d..e7ebf72be 100644
--- a/priv/static/schemas/litepub-0.1.jsonld
+++ b/priv/static/schemas/litepub-0.1.jsonld
@@ -29,7 +29,11 @@
"@id": "litepub:oauthRegistrationEndpoint",
"@type": "@id"
},
- "EmojiReaction": "litepub:EmojiReaction"
+ "EmojiReaction": "litepub:EmojiReaction",
+ "alsoKnownAs": {
+ "@id": "as:alsoKnownAs",
+ "@type": "@id"
+ }
}
]
}
diff --git a/test/fixtures/tesla_mock/admin@mastdon.example.org.json b/test/fixtures/tesla_mock/admin@mastdon.example.org.json
index 8159dc20a..9fdd6557c 100644
--- a/test/fixtures/tesla_mock/admin@mastdon.example.org.json
+++ b/test/fixtures/tesla_mock/admin@mastdon.example.org.json
@@ -9,7 +9,11 @@
"inReplyToAtomUri": "ostatus:inReplyToAtomUri",
"conversation": "ostatus:conversation",
"toot": "http://joinmastodon.org/ns#",
- "Emoji": "toot:Emoji"
+ "Emoji": "toot:Emoji",
+ "alsoKnownAs": {
+ "@id": "as:alsoKnownAs",
+ "@type": "@id"
+ }
}],
"id": "http://mastodon.example.org/users/admin",
"type": "Person",
@@ -50,5 +54,6 @@
"type": "Image",
"mediaType": "image/png",
"url": "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
- }
+ },
+ "alsoKnownAs": ["http://example.org/users/foo"]
}
diff --git a/test/notification_test.exs b/test/notification_test.exs
index f8d429223..dcbffeafe 100644
--- a/test/notification_test.exs
+++ b/test/notification_test.exs
@@ -630,6 +630,35 @@ defmodule Pleroma.NotificationTest do
assert Enum.empty?(Notification.for_user(local_user))
end
+
+ test "move activity generates a notification" do
+ %{ap_id: old_ap_id} = old_user = insert(:user)
+ %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
+ follower = insert(:user)
+ other_follower = insert(:user, %{allow_following_move: false})
+
+ User.follow(follower, old_user)
+ User.follow(other_follower, old_user)
+
+ Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
+ ObanHelpers.perform_all()
+
+ assert [
+ %{
+ activity: %{
+ data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
+ }
+ }
+ ] = Notification.for_user(follower)
+
+ assert [
+ %{
+ activity: %{
+ data: %{"type" => "Move", "actor" => ^old_ap_id, "target" => ^new_ap_id}
+ }
+ }
+ ] = Notification.for_user(other_follower)
+ end
end
describe "for_user" do
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index 30f5dde0c..2677b9e36 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -4,8 +4,11 @@
defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
use Pleroma.DataCase
+ use Oban.Testing, repo: Pleroma.Repo
+
alias Pleroma.Activity
alias Pleroma.Builders.ActivityBuilder
+ alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
@@ -1570,4 +1573,64 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert follow_info.hide_follows == true
end
end
+
+ describe "Move activity" do
+ test "create" do
+ %{ap_id: old_ap_id} = old_user = insert(:user)
+ %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
+ follower = insert(:user)
+ follower_move_opted_out = insert(:user, allow_following_move: false)
+
+ User.follow(follower, old_user)
+ User.follow(follower_move_opted_out, old_user)
+
+ assert User.following?(follower, old_user)
+ assert User.following?(follower_move_opted_out, old_user)
+
+ assert {:ok, activity} = ActivityPub.move(old_user, new_user)
+
+ assert %Activity{
+ actor: ^old_ap_id,
+ data: %{
+ "actor" => ^old_ap_id,
+ "object" => ^old_ap_id,
+ "target" => ^new_ap_id,
+ "type" => "Move"
+ },
+ local: true
+ } = activity
+
+ params = %{
+ "op" => "move_following",
+ "origin_id" => old_user.id,
+ "target_id" => new_user.id
+ }
+
+ assert_enqueued(worker: Pleroma.Workers.BackgroundWorker, args: params)
+
+ Pleroma.Workers.BackgroundWorker.perform(params, nil)
+
+ refute User.following?(follower, old_user)
+ assert User.following?(follower, new_user)
+
+ assert User.following?(follower_move_opted_out, old_user)
+ refute User.following?(follower_move_opted_out, new_user)
+
+ activity = %Activity{activity | object: nil}
+
+ assert [%Notification{activity: ^activity}] =
+ Notification.for_user_since(follower, ~N[2019-04-13 11:22:33])
+
+ assert [%Notification{activity: ^activity}] =
+ Notification.for_user_since(follower_move_opted_out, ~N[2019-04-13 11:22:33])
+ end
+
+ test "old user must be in the new user's `also_known_as` list" do
+ old_user = insert(:user)
+ new_user = insert(:user)
+
+ assert {:error, "Target account must have the origin in `alsoKnownAs`"} =
+ ActivityPub.move(old_user, new_user)
+ end
+ end
end
diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs
index b31c411dc..5da358c43 100644
--- a/test/web/activity_pub/transmogrifier_test.exs
+++ b/test/web/activity_pub/transmogrifier_test.exs
@@ -683,6 +683,37 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert user.bio == "<p>Some bio</p>"
end
+ test "it works with alsoKnownAs" do
+ {:ok, %Activity{data: %{"actor" => actor}}} =
+ "test/fixtures/mastodon-post-activity.json"
+ |> File.read!()
+ |> Poison.decode!()
+ |> Transmogrifier.handle_incoming()
+
+ assert User.get_cached_by_ap_id(actor).also_known_as == ["http://example.org/users/foo"]
+
+ {:ok, _activity} =
+ "test/fixtures/mastodon-update.json"
+ |> File.read!()
+ |> Poison.decode!()
+ |> Map.put("actor", actor)
+ |> Map.update!("object", fn object ->
+ object
+ |> Map.put("actor", actor)
+ |> Map.put("id", actor)
+ |> Map.put("alsoKnownAs", [
+ "http://mastodon.example.org/users/foo",
+ "http://example.org/users/bar"
+ ])
+ end)
+ |> Transmogrifier.handle_incoming()
+
+ assert User.get_cached_by_ap_id(actor).also_known_as == [
+ "http://mastodon.example.org/users/foo",
+ "http://example.org/users/bar"
+ ]
+ end
+
test "it works with custom profile fields" do
{:ok, activity} =
"test/fixtures/mastodon-post-activity.json"
@@ -1272,6 +1303,30 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["cc"]
assert [user.follower_address] == activity.data["to"]
end
+
+ test "it accepts Move activities" do
+ old_user = insert(:user)
+ new_user = insert(:user)
+
+ message = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "type" => "Move",
+ "actor" => old_user.ap_id,
+ "object" => old_user.ap_id,
+ "target" => new_user.ap_id
+ }
+
+ assert :error = Transmogrifier.handle_incoming(message)
+
+ {:ok, _new_user} = User.update_and_set_cache(new_user, %{also_known_as: [old_user.ap_id]})
+
+ assert {:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(message)
+ assert activity.actor == old_user.ap_id
+ assert activity.data["actor"] == old_user.ap_id
+ assert activity.data["object"] == old_user.ap_id
+ assert activity.data["target"] == new_user.ap_id
+ assert activity.data["type"] == "Move"
+ end
end
describe "prepare outgoing" do
diff --git a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs
index 519b56d6c..77cfce4fa 100644
--- a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs
+++ b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs
@@ -103,6 +103,21 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do
assert user["locked"] == true
end
+ test "updates the user's allow_following_move", %{conn: conn} do
+ user = insert(:user)
+
+ assert user.allow_following_move == true
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{allow_following_move: "false"})
+
+ assert refresh_record(user).allow_following_move == false
+ assert user = json_response(conn, 200)
+ assert user["pleroma"]["allow_following_move"] == false
+ end
+
test "updates the user's default scope", %{conn: conn} do
user = insert(:user)
diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs
index d147079ab..35aefb7dc 100644
--- a/test/web/mastodon_api/views/account_view_test.exs
+++ b/test/web/mastodon_api/views/account_view_test.exs
@@ -102,7 +102,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
privacy = user.default_scope
assert %{
- pleroma: %{notification_settings: ^notification_settings},
+ pleroma: %{notification_settings: ^notification_settings, allow_following_move: true},
source: %{privacy: ^privacy}
} = AccountView.render("show.json", %{user: user, for: user})
end
diff --git a/test/web/mastodon_api/views/notification_view_test.exs b/test/web/mastodon_api/views/notification_view_test.exs
index c9043a69a..80b6d414c 100644
--- a/test/web/mastodon_api/views/notification_view_test.exs
+++ b/test/web/mastodon_api/views/notification_view_test.exs
@@ -107,4 +107,28 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
assert [] ==
NotificationView.render("index.json", %{notifications: [notification], for: followed})
end
+
+ test "Move notification" do
+ %{ap_id: old_ap_id} = old_user = insert(:user)
+ %{ap_id: _new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
+ follower = insert(:user)
+
+ User.follow(follower, old_user)
+ Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
+ Pleroma.Tests.ObanHelpers.perform_all()
+
+ [notification] = Notification.for_user(follower)
+
+ expected = %{
+ id: to_string(notification.id),
+ pleroma: %{is_seen: false},
+ type: "move",
+ account: AccountView.render("show.json", %{user: old_user, for: follower}),
+ target: AccountView.render("show.json", %{user: new_user, for: follower}),
+ created_at: Utils.to_masto_date(notification.inserted_at)
+ }
+
+ assert [expected] ==
+ NotificationView.render("index.json", %{notifications: [notification], for: follower})
+ end
end