forked from AkkomaGang/akkoma
FloatingGhost
98cb255d12
OTP builds to 1.15 Changelog entry Ensure policies are fully loaded Fix :warn use main branch for linkify Fix warn in tests Migrations for phoenix 1.17 Revert "Migrations for phoenix 1.17" This reverts commit 6a3b2f15b74ea5e33150529385215b7a531f3999. Oban upgrade Add default empty whitelist mix format limit test to amd64 OTP 26 tests for 1.15 use OTP_VERSION tag baka just 1.15 Massive deps update Update locale, deps Mix format shell???? multiline??? ? max cases 1 use assert_recieve don't put_env in async tests don't async conn/fs tests mix format FIx some uploader issues Fix tests
1457 lines
46 KiB
Elixir
1457 lines
46 KiB
Elixir
# Pleroma: A lightweight social networking server
|
|
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
|
# SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
defmodule Pleroma.Web.CommonAPITest do
|
|
use Oban.Testing, repo: Pleroma.Repo
|
|
use Pleroma.DataCase, async: false
|
|
|
|
alias Pleroma.Activity
|
|
alias Pleroma.Conversation.Participation
|
|
alias Pleroma.Notification
|
|
alias Pleroma.Object
|
|
alias Pleroma.Repo
|
|
alias Pleroma.User
|
|
alias Pleroma.Web.ActivityPub.Transmogrifier
|
|
alias Pleroma.Web.ActivityPub.Visibility
|
|
alias Pleroma.Web.AdminAPI.AccountView
|
|
alias Pleroma.Web.CommonAPI
|
|
alias Pleroma.Workers.PollWorker
|
|
|
|
import Pleroma.Factory
|
|
import Mock
|
|
import Ecto.Query, only: [from: 2]
|
|
|
|
require Pleroma.Constants
|
|
|
|
setup_all do
|
|
clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
|
|
clear_config([Pleroma.Uploaders.Local, :uploads], "uploads")
|
|
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
|
:ok
|
|
end
|
|
|
|
setup do: clear_config([:instance, :safe_dm_mentions])
|
|
setup do: clear_config([:instance, :limit])
|
|
setup do: clear_config([:instance, :max_pinned_statuses])
|
|
|
|
describe "posting polls" do
|
|
test "it posts a poll" do
|
|
user = insert(:user)
|
|
|
|
{:ok, activity} =
|
|
CommonAPI.post(user, %{
|
|
status: "who is the best",
|
|
poll: %{expires_in: 600, options: ["reimu", "marisa"]}
|
|
})
|
|
|
|
object = Object.normalize(activity, fetch: false)
|
|
|
|
assert object.data["type"] == "Question"
|
|
assert object.data["oneOf"] |> length() == 2
|
|
|
|
{:ok, time, _} = DateTime.from_iso8601(object.data["closed"])
|
|
|
|
assert_enqueued(
|
|
worker: PollWorker,
|
|
args: %{op: "poll_end", activity_id: activity.id},
|
|
scheduled_at: time
|
|
)
|
|
end
|
|
end
|
|
|
|
describe "blocking" do
|
|
setup do
|
|
blocker = insert(:user)
|
|
blocked = insert(:user, local: false)
|
|
CommonAPI.follow(blocker, blocked)
|
|
CommonAPI.follow(blocked, blocker)
|
|
CommonAPI.accept_follow_request(blocker, blocked)
|
|
CommonAPI.accept_follow_request(blocked, blocked)
|
|
%{blocker: blocker, blocked: blocked}
|
|
end
|
|
|
|
test "it blocks and federates", %{blocker: blocker, blocked: blocked} do
|
|
clear_config([:instance, :federating], true)
|
|
clear_config([:activitypub, :outgoing_blocks], true)
|
|
|
|
with_mock Pleroma.Web.Federator,
|
|
publish: fn _ -> nil end do
|
|
assert User.get_follow_state(blocker, blocked) == :follow_accept
|
|
refute is_nil(Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(blocker, blocked))
|
|
|
|
assert {:ok, block} = CommonAPI.block(blocker, blocked)
|
|
|
|
assert block.local
|
|
assert User.blocks?(blocker, blocked)
|
|
refute User.following?(blocker, blocked)
|
|
refute User.following?(blocked, blocker)
|
|
|
|
refute User.get_follow_state(blocker, blocked)
|
|
|
|
assert %{data: %{"state" => "reject"}} =
|
|
Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(blocker, blocked)
|
|
|
|
assert called(Pleroma.Web.Federator.publish(block))
|
|
end
|
|
end
|
|
|
|
test "it blocks and does not federate if outgoing blocks are disabled", %{
|
|
blocker: blocker,
|
|
blocked: blocked
|
|
} do
|
|
clear_config([:instance, :federating], true)
|
|
clear_config([:activitypub, :outgoing_blocks], false)
|
|
|
|
with_mock Pleroma.Web.Federator,
|
|
publish: fn _ -> nil end do
|
|
assert {:ok, block} = CommonAPI.block(blocker, blocked)
|
|
|
|
assert block.local
|
|
assert User.blocks?(blocker, blocked)
|
|
refute User.following?(blocker, blocked)
|
|
refute User.following?(blocked, blocker)
|
|
|
|
refute called(Pleroma.Web.Federator.publish(block))
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "unblocking" do
|
|
test "it works even without an existing block activity" do
|
|
blocked = insert(:user)
|
|
blocker = insert(:user)
|
|
User.block(blocker, blocked)
|
|
|
|
assert User.blocks?(blocker, blocked)
|
|
assert {:ok, :no_activity} == CommonAPI.unblock(blocker, blocked)
|
|
refute User.blocks?(blocker, blocked)
|
|
end
|
|
end
|
|
|
|
describe "deletion" do
|
|
test "it works with pruned objects" do
|
|
user = insert(:user)
|
|
|
|
{:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
|
|
|
|
clear_config([:instance, :federating], true)
|
|
|
|
Object.normalize(post, fetch: false)
|
|
|> Object.prune()
|
|
|
|
with_mock Pleroma.Web.Federator,
|
|
publish: fn _ -> nil end do
|
|
assert {:ok, delete} = CommonAPI.delete(post.id, user)
|
|
assert delete.local
|
|
assert called(Pleroma.Web.Federator.publish(delete))
|
|
end
|
|
|
|
refute Activity.get_by_id(post.id)
|
|
end
|
|
|
|
test "it allows users to delete their posts" do
|
|
user = insert(:user)
|
|
|
|
{:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
|
|
|
|
clear_config([:instance, :federating], true)
|
|
|
|
with_mock Pleroma.Web.Federator,
|
|
publish: fn _ -> nil end do
|
|
assert {:ok, delete} = CommonAPI.delete(post.id, user)
|
|
assert delete.local
|
|
assert called(Pleroma.Web.Federator.publish(delete))
|
|
end
|
|
|
|
refute Activity.get_by_id(post.id)
|
|
end
|
|
|
|
test "it does not allow a user to delete their posts" do
|
|
user = insert(:user)
|
|
other_user = insert(:user)
|
|
|
|
{:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
|
|
|
|
assert {:error, "Could not delete"} = CommonAPI.delete(post.id, other_user)
|
|
assert Activity.get_by_id(post.id)
|
|
end
|
|
|
|
test "it allows moderators to delete other user's posts" do
|
|
user = insert(:user)
|
|
moderator = insert(:user, is_moderator: true)
|
|
|
|
{:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
|
|
|
|
assert {:ok, delete} = CommonAPI.delete(post.id, moderator)
|
|
assert delete.local
|
|
|
|
refute Activity.get_by_id(post.id)
|
|
end
|
|
|
|
test "it allows admins to delete other user's posts" do
|
|
user = insert(:user)
|
|
moderator = insert(:user, is_admin: true)
|
|
|
|
{:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
|
|
|
|
assert {:ok, delete} = CommonAPI.delete(post.id, moderator)
|
|
assert delete.local
|
|
|
|
refute Activity.get_by_id(post.id)
|
|
end
|
|
|
|
test "superusers deleting non-local posts won't federate the delete" do
|
|
# This is the user of the ingested activity
|
|
_user =
|
|
insert(:user,
|
|
local: false,
|
|
ap_id: "http://mastodon.example.org/users/admin",
|
|
last_refreshed_at: NaiveDateTime.utc_now()
|
|
)
|
|
|
|
moderator = insert(:user, is_admin: true)
|
|
|
|
data =
|
|
File.read!("test/fixtures/mastodon-post-activity.json")
|
|
|> Jason.decode!()
|
|
|
|
{:ok, post} = Transmogrifier.handle_incoming(data)
|
|
|
|
with_mock Pleroma.Web.Federator,
|
|
publish: fn _ -> nil end do
|
|
assert {:ok, delete} = CommonAPI.delete(post.id, moderator)
|
|
assert delete.local
|
|
refute called(Pleroma.Web.Federator.publish(:_))
|
|
end
|
|
|
|
refute Activity.get_by_id(post.id)
|
|
end
|
|
|
|
test "it allows privileged users to delete banned user's posts" do
|
|
clear_config([:instance, :moderator_privileges], [:messages_delete])
|
|
user = insert(:user)
|
|
moderator = insert(:user, is_moderator: true)
|
|
|
|
{:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
|
|
User.set_activation(user, false)
|
|
|
|
assert {:ok, delete} = CommonAPI.delete(post.id, moderator)
|
|
assert delete.local
|
|
|
|
refute Activity.get_by_id(post.id)
|
|
end
|
|
end
|
|
|
|
test "favoriting race condition" do
|
|
user = insert(:user)
|
|
users_serial = insert_list(10, :user)
|
|
users = insert_list(10, :user)
|
|
|
|
{:ok, activity} = CommonAPI.post(user, %{status: "."})
|
|
|
|
users_serial
|
|
|> Enum.map(fn user ->
|
|
CommonAPI.favorite(user, activity.id)
|
|
end)
|
|
|
|
object = Object.get_by_ap_id(activity.data["object"])
|
|
assert object.data["like_count"] == 10
|
|
|
|
users
|
|
|> Enum.map(fn user ->
|
|
Task.async(fn ->
|
|
CommonAPI.favorite(user, activity.id)
|
|
end)
|
|
end)
|
|
|> Enum.map(&Task.await/1)
|
|
|
|
object = Object.get_by_ap_id(activity.data["object"])
|
|
assert object.data["like_count"] == 20
|
|
end
|
|
|
|
test "repeating race condition" do
|
|
user = insert(:user)
|
|
users_serial = insert_list(10, :user)
|
|
users = insert_list(10, :user)
|
|
|
|
{:ok, activity} = CommonAPI.post(user, %{status: "."})
|
|
|
|
users_serial
|
|
|> Enum.map(fn user ->
|
|
CommonAPI.repeat(activity.id, user)
|
|
end)
|
|
|
|
object = Object.get_by_ap_id(activity.data["object"])
|
|
assert object.data["announcement_count"] == 10
|
|
|
|
users
|
|
|> Enum.map(fn user ->
|
|
Task.async(fn ->
|
|
CommonAPI.repeat(activity.id, user)
|
|
end)
|
|
end)
|
|
|> Enum.map(&Task.await/1)
|
|
|
|
object = Object.get_by_ap_id(activity.data["object"])
|
|
assert object.data["announcement_count"] == 20
|
|
end
|
|
|
|
test "when replying to a conversation / participation, it will set the correct context id even if no explicit reply_to is given" do
|
|
user = insert(:user)
|
|
{:ok, activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"})
|
|
|
|
[participation] = Participation.for_user(user)
|
|
|
|
{:ok, convo_reply} =
|
|
CommonAPI.post(user, %{status: ".", in_reply_to_conversation_id: participation.id})
|
|
|
|
assert Visibility.is_direct?(convo_reply)
|
|
|
|
assert activity.data["context"] == convo_reply.data["context"]
|
|
end
|
|
|
|
test "when replying to a conversation / participation, it only mentions the recipients explicitly declared in the participation" do
|
|
har = insert(:user)
|
|
jafnhar = insert(:user)
|
|
tridi = insert(:user)
|
|
|
|
{:ok, activity} =
|
|
CommonAPI.post(har, %{
|
|
status: "@#{jafnhar.nickname} hey",
|
|
visibility: "direct"
|
|
})
|
|
|
|
assert har.ap_id in activity.recipients
|
|
assert jafnhar.ap_id in activity.recipients
|
|
|
|
[participation] = Participation.for_user(har)
|
|
|
|
{:ok, activity} =
|
|
CommonAPI.post(har, %{
|
|
status: "I don't really like @#{tridi.nickname}",
|
|
visibility: "direct",
|
|
in_reply_to_status_id: activity.id,
|
|
in_reply_to_conversation_id: participation.id
|
|
})
|
|
|
|
assert har.ap_id in activity.recipients
|
|
assert jafnhar.ap_id in activity.recipients
|
|
refute tridi.ap_id in activity.recipients
|
|
end
|
|
|
|
test "with the safe_dm_mention option set, it does not mention people beyond the initial tags" do
|
|
har = insert(:user)
|
|
jafnhar = insert(:user)
|
|
tridi = insert(:user)
|
|
|
|
clear_config([:instance, :safe_dm_mentions], true)
|
|
|
|
{:ok, activity} =
|
|
CommonAPI.post(har, %{
|
|
status: "@#{jafnhar.nickname} hey, i never want to see @#{tridi.nickname} again",
|
|
visibility: "direct"
|
|
})
|
|
|
|
refute tridi.ap_id in activity.recipients
|
|
assert jafnhar.ap_id in activity.recipients
|
|
end
|
|
|
|
test "it de-duplicates tags" do
|
|
user = insert(:user)
|
|
{:ok, activity} = CommonAPI.post(user, %{status: "#2hu #2HU"})
|
|
|
|
object = Object.normalize(activity, fetch: false)
|
|
|
|
assert Object.tags(object) == ["2hu"]
|
|
end
|
|
|
|
test "it adds emoji in the object" do
|
|
user = insert(:user)
|
|
{:ok, activity} = CommonAPI.post(user, %{status: ":firefox:"})
|
|
|
|
assert Object.normalize(activity, fetch: false).data["emoji"]["firefox"]
|
|
end
|
|
|
|
describe "posting" do
|
|
test "it adds an emoji on an external site" do
|
|
user = insert(:user)
|
|
{:ok, activity} = CommonAPI.post(user, %{status: "hey :external_emoji:"})
|
|
|
|
assert %{"external_emoji" => url} = Object.normalize(activity).data["emoji"]
|
|
assert url == "https://example.com/emoji.png"
|
|
|
|
{:ok, activity} = CommonAPI.post(user, %{status: "hey :blank:"})
|
|
|
|
assert %{"blank" => url} = Object.normalize(activity).data["emoji"]
|
|
assert url == "#{Pleroma.Web.Endpoint.url()}/emoji/blank.png"
|
|
end
|
|
|
|
test "it copies emoji from the subject of the parent post" do
|
|
%Object{} =
|
|
object =
|
|
Object.normalize("https://patch.cx/objects/a399c28e-c821-4820-bc3e-4afeb044c16f",
|
|
fetch: true
|
|
)
|
|
|
|
activity = Activity.get_create_by_object_ap_id(object.data["id"])
|
|
user = insert(:user)
|
|
|
|
{:ok, reply_activity} =
|
|
CommonAPI.post(user, %{
|
|
in_reply_to_id: activity.id,
|
|
status: ":joker_disapprove:",
|
|
spoiler_text: ":joker_smile:"
|
|
})
|
|
|
|
assert Object.normalize(reply_activity).data["emoji"]["joker_smile"]
|
|
refute Object.normalize(reply_activity).data["emoji"]["joker_disapprove"]
|
|
end
|
|
|
|
test "deactivated users can't post" do
|
|
user = insert(:user, is_active: false)
|
|
assert {:error, _} = CommonAPI.post(user, %{status: "ye"})
|
|
end
|
|
|
|
test "it supports explicit addressing" do
|
|
user = insert(:user)
|
|
user_two = insert(:user)
|
|
user_three = insert(:user)
|
|
user_four = insert(:user)
|
|
|
|
{:ok, activity} =
|
|
CommonAPI.post(user, %{
|
|
status:
|
|
"Hey, I think @#{user_three.nickname} is ugly. @#{user_four.nickname} is alright though.",
|
|
to: [user_two.nickname, user_four.nickname, "nonexistent"]
|
|
})
|
|
|
|
assert user.ap_id in activity.recipients
|
|
assert user_two.ap_id in activity.recipients
|
|
assert user_four.ap_id in activity.recipients
|
|
refute user_three.ap_id in activity.recipients
|
|
end
|
|
|
|
test "it filters out obviously bad tags when accepting a post as HTML" do
|
|
user = insert(:user)
|
|
|
|
post = "<p><b>2hu</b></p><script>alert('xss')</script>"
|
|
|
|
{:ok, activity} =
|
|
CommonAPI.post(user, %{
|
|
status: post,
|
|
content_type: "text/html"
|
|
})
|
|
|
|
object = Object.normalize(activity, fetch: false)
|
|
|
|
assert object.data["content"] == "<p><b>2hu</b></p>alert('xss')"
|
|
|
|
assert object.data["source"] == %{
|
|
"mediaType" => "text/html",
|
|
"content" => post
|
|
}
|
|
end
|
|
|
|
test "it filters out obviously bad tags when accepting a post as Markdown" do
|
|
user = insert(:user)
|
|
|
|
post = "<p><b>2hu</b></p><script>alert('xss')</script>"
|
|
|
|
{:ok, activity} =
|
|
CommonAPI.post(user, %{
|
|
status: post,
|
|
content_type: "text/markdown"
|
|
})
|
|
|
|
object = Object.normalize(activity, fetch: false)
|
|
|
|
assert object.data["content"] == "<p><b>2hu</b></p>"
|
|
|
|
assert object.data["source"] == %{
|
|
"mediaType" => "text/markdown",
|
|
"content" => post
|
|
}
|
|
end
|
|
|
|
test "it does not allow replies to direct messages that are not direct messages themselves" do
|
|
user = insert(:user)
|
|
|
|
{:ok, activity} = CommonAPI.post(user, %{status: "suya..", visibility: "direct"})
|
|
|
|
assert {:ok, _} =
|
|
CommonAPI.post(user, %{
|
|
status: "suya..",
|
|
visibility: "direct",
|
|
in_reply_to_status_id: activity.id
|
|
})
|
|
|
|
Enum.each(["public", "private", "unlisted"], fn visibility ->
|
|
assert {:error, "The message visibility must be direct"} =
|
|
CommonAPI.post(user, %{
|
|
status: "suya..",
|
|
visibility: visibility,
|
|
in_reply_to_status_id: activity.id
|
|
})
|
|
end)
|
|
end
|
|
|
|
test "replying with a direct message will NOT auto-add the author of the reply to the recipient list" do
|
|
user = insert(:user)
|
|
other_user = insert(:user)
|
|
third_user = insert(:user)
|
|
|
|
{:ok, post} = CommonAPI.post(user, %{status: "I'm stupid"})
|
|
|
|
{:ok, open_answer} =
|
|
CommonAPI.post(other_user, %{status: "No ur smart", in_reply_to_status_id: post.id})
|
|
|
|
# The OP is implicitly added
|
|
assert user.ap_id in open_answer.recipients
|
|
|
|
{:ok, secret_answer} =
|
|
CommonAPI.post(other_user, %{
|
|
status: "lol, that guy really is stupid, right, @#{third_user.nickname}?",
|
|
in_reply_to_status_id: post.id,
|
|
visibility: "direct"
|
|
})
|
|
|
|
assert third_user.ap_id in secret_answer.recipients
|
|
|
|
# The OP is not added
|
|
refute user.ap_id in secret_answer.recipients
|
|
end
|
|
|
|
test "it allows to address a list" do
|
|
user = insert(:user)
|
|
{:ok, list} = Pleroma.List.create("foo", user)
|
|
|
|
{:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"})
|
|
|
|
assert activity.data["bcc"] == [list.ap_id]
|
|
assert activity.recipients == [list.ap_id, user.ap_id]
|
|
assert activity.data["listMessage"] == list.ap_id
|
|
end
|
|
|
|
test "it returns error when status is empty and no attachments" do
|
|
user = insert(:user)
|
|
|
|
assert {:error, "Cannot post an empty status without attachments"} =
|
|
CommonAPI.post(user, %{status: ""})
|
|
end
|
|
|
|
test "it validates character limits are correctly enforced" do
|
|
clear_config([:instance, :limit], 5)
|
|
|
|
user = insert(:user)
|
|
|
|
assert {:error, "The status is over the character limit"} =
|
|
CommonAPI.post(user, %{status: "foobar"})
|
|
|
|
assert {:ok, _activity} = CommonAPI.post(user, %{status: "12345"})
|
|
end
|
|
|
|
test "it can handle activities that expire" do
|
|
user = insert(:user)
|
|
|
|
expires_at = DateTime.add(DateTime.utc_now(), 1_000_000)
|
|
|
|
assert {:ok, activity} = CommonAPI.post(user, %{status: "chai", expires_in: 1_000_000})
|
|
|
|
assert_enqueued(
|
|
worker: Pleroma.Workers.PurgeExpiredActivity,
|
|
args: %{activity_id: activity.id},
|
|
scheduled_at: expires_at
|
|
)
|
|
end
|
|
end
|
|
|
|
describe "reactions" do
|
|
test "reacting to a status with an emoji" do
|
|
user = insert(:user)
|
|
other_user = insert(:user)
|
|
|
|
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
|
|
|
|
{:ok, reaction} = CommonAPI.react_with_emoji(activity.id, user, "👍")
|
|
|
|
assert reaction.data["actor"] == user.ap_id
|
|
assert reaction.data["content"] == "👍"
|
|
|
|
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
|
|
|
|
{:error, _} = CommonAPI.react_with_emoji(activity.id, user, ".")
|
|
end
|
|
|
|
test "unreacting to a status with an emoji" do
|
|
user = insert(:user)
|
|
other_user = insert(:user)
|
|
|
|
clear_config([:instance, :federating], true)
|
|
|
|
with_mock Pleroma.Web.Federator,
|
|
publish: fn _ -> nil end do
|
|
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
|
|
{:ok, reaction} = CommonAPI.react_with_emoji(activity.id, user, "👍")
|
|
|
|
{:ok, unreaction} = CommonAPI.unreact_with_emoji(activity.id, user, "👍")
|
|
|
|
assert unreaction.data["type"] == "Undo"
|
|
assert unreaction.data["object"] == reaction.data["id"]
|
|
assert unreaction.local
|
|
|
|
# On federation, it contains the undone (and deleted) object
|
|
unreaction_with_object = %{
|
|
unreaction
|
|
| data: Map.put(unreaction.data, "object", reaction.data)
|
|
}
|
|
|
|
assert called(Pleroma.Web.Federator.publish(unreaction_with_object))
|
|
end
|
|
end
|
|
|
|
test "repeating a status" do
|
|
user = insert(:user)
|
|
other_user = insert(:user)
|
|
|
|
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
|
|
|
|
{:ok, %Activity{} = announce_activity} = CommonAPI.repeat(activity.id, user)
|
|
assert Visibility.is_public?(announce_activity)
|
|
end
|
|
|
|
test "can't repeat a repeat" do
|
|
user = insert(:user)
|
|
other_user = insert(:user)
|
|
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
|
|
|
|
{:ok, %Activity{} = announce} = CommonAPI.repeat(activity.id, other_user)
|
|
|
|
refute match?({:ok, %Activity{}}, CommonAPI.repeat(announce.id, user))
|
|
end
|
|
|
|
test "repeating a status privately" do
|
|
user = insert(:user)
|
|
other_user = insert(:user)
|
|
|
|
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
|
|
|
|
{:ok, %Activity{} = announce_activity} =
|
|
CommonAPI.repeat(activity.id, user, %{visibility: "private"})
|
|
|
|
assert Visibility.is_private?(announce_activity)
|
|
refute Visibility.visible_for_user?(announce_activity, nil)
|
|
end
|
|
|
|
test "author can repeat own private statuses" do
|
|
author = insert(:user)
|
|
follower = insert(:user)
|
|
CommonAPI.follow(follower, author)
|
|
|
|
{:ok, activity} = CommonAPI.post(author, %{status: "cofe", visibility: "private"})
|
|
|
|
{:ok, %Activity{} = announce_activity} = CommonAPI.repeat(activity.id, author)
|
|
|
|
assert Visibility.is_private?(announce_activity)
|
|
refute Visibility.visible_for_user?(announce_activity, nil)
|
|
|
|
assert Visibility.visible_for_user?(activity, follower)
|
|
assert {:error, :not_found} = CommonAPI.repeat(activity.id, follower)
|
|
end
|
|
|
|
test "favoriting a status" do
|
|
user = insert(:user)
|
|
other_user = insert(:user)
|
|
|
|
{:ok, post_activity} = CommonAPI.post(other_user, %{status: "cofe"})
|
|
|
|
{:ok, %Activity{data: data}} = CommonAPI.favorite(user, post_activity.id)
|
|
assert data["type"] == "Like"
|
|
assert data["actor"] == user.ap_id
|
|
assert data["object"] == post_activity.data["object"]
|
|
end
|
|
|
|
test "retweeting a status twice returns the status" do
|
|
user = insert(:user)
|
|
other_user = insert(:user)
|
|
|
|
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
|
|
{:ok, %Activity{} = announce} = CommonAPI.repeat(activity.id, user)
|
|
{:ok, ^announce} = CommonAPI.repeat(activity.id, user)
|
|
end
|
|
|
|
test "favoriting a status twice returns ok, but without the like activity" do
|
|
user = insert(:user)
|
|
other_user = insert(:user)
|
|
|
|
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe"})
|
|
{:ok, %Activity{}} = CommonAPI.favorite(user, activity.id)
|
|
assert {:ok, :already_liked} = CommonAPI.favorite(user, activity.id)
|
|
end
|
|
end
|
|
|
|
describe "pinned statuses" do
|
|
setup do
|
|
clear_config([:instance, :max_pinned_statuses], 1)
|
|
|
|
user = insert(:user)
|
|
{:ok, activity} = CommonAPI.post(user, %{status: "HI!!!"})
|
|
|
|
[user: user, activity: activity]
|
|
end
|
|
|
|
test "activity not found error", %{user: user} do
|
|
assert {:error, :not_found} = CommonAPI.pin("id", user)
|
|
end
|
|
|
|
test "pin status", %{user: user, activity: activity} do
|
|
assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
|
|
|
|
%{data: %{"id" => object_id}} = Object.normalize(activity)
|
|
user = refresh_record(user)
|
|
|
|
assert user.pinned_objects |> Map.keys() == [object_id]
|
|
end
|
|
|
|
test "pin poll", %{user: user} do
|
|
{:ok, activity} =
|
|
CommonAPI.post(user, %{
|
|
status: "How is fediverse today?",
|
|
poll: %{options: ["Absolutely outstanding", "Not good"], expires_in: 20}
|
|
})
|
|
|
|
assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
|
|
|
|
%{data: %{"id" => object_id}} = Object.normalize(activity)
|
|
|
|
user = refresh_record(user)
|
|
|
|
assert user.pinned_objects |> Map.keys() == [object_id]
|
|
end
|
|
|
|
test "unlisted statuses can be pinned", %{user: user} do
|
|
{:ok, activity} = CommonAPI.post(user, %{status: "HI!!!", visibility: "unlisted"})
|
|
assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
|
|
end
|
|
|
|
test "only self-authored can be pinned", %{activity: activity} do
|
|
user = insert(:user)
|
|
|
|
assert {:error, :ownership_error} = CommonAPI.pin(activity.id, user)
|
|
end
|
|
|
|
test "max pinned statuses", %{user: user, activity: activity_one} do
|
|
{:ok, activity_two} = CommonAPI.post(user, %{status: "HI!!!"})
|
|
|
|
assert {:ok, ^activity_one} = CommonAPI.pin(activity_one.id, user)
|
|
|
|
user = refresh_record(user)
|
|
|
|
assert {:error, :pinned_statuses_limit_reached} = CommonAPI.pin(activity_two.id, user)
|
|
end
|
|
|
|
test "only public can be pinned", %{user: user} do
|
|
{:ok, activity} = CommonAPI.post(user, %{status: "private status", visibility: "private"})
|
|
{:error, :visibility_error} = CommonAPI.pin(activity.id, user)
|
|
end
|
|
|
|
test "unpin status", %{user: user, activity: activity} do
|
|
{:ok, activity} = CommonAPI.pin(activity.id, user)
|
|
|
|
user = refresh_record(user)
|
|
|
|
id = activity.id
|
|
|
|
assert match?({:ok, %{id: ^id}}, CommonAPI.unpin(activity.id, user))
|
|
|
|
user = refresh_record(user)
|
|
|
|
assert user.pinned_objects == %{}
|
|
end
|
|
|
|
test "should unpin when deleting a status", %{user: user, activity: activity} do
|
|
{:ok, activity} = CommonAPI.pin(activity.id, user)
|
|
|
|
user = refresh_record(user)
|
|
|
|
assert {:ok, _} = CommonAPI.delete(activity.id, user)
|
|
|
|
user = refresh_record(user)
|
|
|
|
assert user.pinned_objects == %{}
|
|
end
|
|
|
|
test "ephemeral activity won't be deleted if was pinned", %{user: user} do
|
|
{:ok, activity} = CommonAPI.post(user, %{status: "Hello!", expires_in: 601})
|
|
|
|
assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id)
|
|
|
|
{:ok, _activity} = CommonAPI.pin(activity.id, user)
|
|
refute Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id)
|
|
|
|
user = refresh_record(user)
|
|
{:ok, _} = CommonAPI.unpin(activity.id, user)
|
|
|
|
# recreates expiration job on unpin
|
|
assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id)
|
|
end
|
|
|
|
test "ephemeral activity deletion job won't be deleted on pinning error", %{
|
|
user: user,
|
|
activity: activity
|
|
} do
|
|
clear_config([:instance, :max_pinned_statuses], 1)
|
|
|
|
{:ok, _activity} = CommonAPI.pin(activity.id, user)
|
|
|
|
{:ok, activity2} = CommonAPI.post(user, %{status: "another status", expires_in: 601})
|
|
|
|
assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity2.id)
|
|
|
|
user = refresh_record(user)
|
|
{:error, :pinned_statuses_limit_reached} = CommonAPI.pin(activity2.id, user)
|
|
|
|
assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity2.id)
|
|
end
|
|
end
|
|
|
|
describe "mute tests" do
|
|
setup do
|
|
user = insert(:user)
|
|
|
|
activity = insert(:note_activity)
|
|
|
|
[user: user, activity: activity]
|
|
end
|
|
|
|
test "marks notifications as read after mute" do
|
|
author = insert(:user)
|
|
activity = insert(:note_activity, user: author)
|
|
|
|
friend1 = insert(:user)
|
|
friend2 = insert(:user)
|
|
|
|
{:ok, reply_activity} =
|
|
CommonAPI.post(
|
|
friend2,
|
|
%{
|
|
status: "@#{author.nickname} @#{friend1.nickname} test reply",
|
|
in_reply_to_status_id: activity.id
|
|
}
|
|
)
|
|
|
|
{:ok, favorite_activity} = CommonAPI.favorite(friend2, activity.id)
|
|
{:ok, repeat_activity} = CommonAPI.repeat(activity.id, friend1)
|
|
|
|
assert Repo.aggregate(
|
|
from(n in Notification, where: n.seen == false and n.user_id == ^friend1.id),
|
|
:count
|
|
) == 1
|
|
|
|
unread_notifications =
|
|
Repo.all(from(n in Notification, where: n.seen == false, where: n.user_id == ^author.id))
|
|
|
|
assert Enum.any?(unread_notifications, fn n ->
|
|
n.type == "favourite" && n.activity_id == favorite_activity.id
|
|
end)
|
|
|
|
assert Enum.any?(unread_notifications, fn n ->
|
|
n.type == "reblog" && n.activity_id == repeat_activity.id
|
|
end)
|
|
|
|
assert Enum.any?(unread_notifications, fn n ->
|
|
n.type == "mention" && n.activity_id == reply_activity.id
|
|
end)
|
|
|
|
{:ok, _} = CommonAPI.add_mute(author, activity)
|
|
assert CommonAPI.thread_muted?(author, activity)
|
|
|
|
assert Repo.aggregate(
|
|
from(n in Notification, where: n.seen == false and n.user_id == ^friend1.id),
|
|
:count
|
|
) == 1
|
|
|
|
read_notifications =
|
|
Repo.all(from(n in Notification, where: n.seen == true, where: n.user_id == ^author.id))
|
|
|
|
assert Enum.any?(read_notifications, fn n ->
|
|
n.type == "favourite" && n.activity_id == favorite_activity.id
|
|
end)
|
|
|
|
assert Enum.any?(read_notifications, fn n ->
|
|
n.type == "reblog" && n.activity_id == repeat_activity.id
|
|
end)
|
|
|
|
assert Enum.any?(read_notifications, fn n ->
|
|
n.type == "mention" && n.activity_id == reply_activity.id
|
|
end)
|
|
end
|
|
|
|
test "add mute", %{user: user, activity: activity} do
|
|
{:ok, _} = CommonAPI.add_mute(user, activity)
|
|
assert CommonAPI.thread_muted?(user, activity)
|
|
end
|
|
|
|
test "add expiring mute", %{user: user, activity: activity} do
|
|
{:ok, _} = CommonAPI.add_mute(user, activity, %{expires_in: 60})
|
|
assert CommonAPI.thread_muted?(user, activity)
|
|
|
|
worker = Pleroma.Workers.MuteExpireWorker
|
|
args = %{"op" => "unmute_conversation", "user_id" => user.id, "activity_id" => activity.id}
|
|
|
|
assert_enqueued(
|
|
worker: worker,
|
|
args: args
|
|
)
|
|
|
|
assert :ok = perform_job(worker, args)
|
|
refute CommonAPI.thread_muted?(user, activity)
|
|
end
|
|
|
|
test "remove mute", %{user: user, activity: activity} do
|
|
CommonAPI.add_mute(user, activity)
|
|
{:ok, _} = CommonAPI.remove_mute(user, activity)
|
|
refute CommonAPI.thread_muted?(user, activity)
|
|
end
|
|
|
|
test "remove mute by ids", %{user: user, activity: activity} do
|
|
CommonAPI.add_mute(user, activity)
|
|
{:ok, _} = CommonAPI.remove_mute(user.id, activity.id)
|
|
refute CommonAPI.thread_muted?(user, activity)
|
|
end
|
|
|
|
test "check that mutes can't be duplicate", %{user: user, activity: activity} do
|
|
CommonAPI.add_mute(user, activity)
|
|
{:error, _} = CommonAPI.add_mute(user, activity)
|
|
end
|
|
end
|
|
|
|
describe "reports" do
|
|
test "creates a report" do
|
|
reporter = insert(:user)
|
|
target_user = insert(:user)
|
|
|
|
{:ok, activity} = CommonAPI.post(target_user, %{status: "foobar"})
|
|
|
|
reporter_ap_id = reporter.ap_id
|
|
target_ap_id = target_user.ap_id
|
|
activity_ap_id = activity.data["id"]
|
|
comment = "foobar"
|
|
|
|
report_data = %{
|
|
account_id: target_user.id,
|
|
comment: comment,
|
|
status_ids: [activity.id]
|
|
}
|
|
|
|
note_obj = %{
|
|
"type" => "Note",
|
|
"id" => activity_ap_id,
|
|
"content" => "foobar",
|
|
"published" => activity.object.data["published"],
|
|
"actor" => AccountView.render("show.json", %{user: target_user})
|
|
}
|
|
|
|
assert {:ok, flag_activity} = CommonAPI.report(reporter, report_data)
|
|
|
|
assert %Activity{
|
|
actor: ^reporter_ap_id,
|
|
data: %{
|
|
"type" => "Flag",
|
|
"content" => ^comment,
|
|
"object" => [^target_ap_id, ^note_obj],
|
|
"state" => "open"
|
|
}
|
|
} = flag_activity
|
|
end
|
|
|
|
test "updates report state" do
|
|
[reporter, target_user] = insert_pair(:user)
|
|
activity = insert(:note_activity, user: target_user)
|
|
|
|
{:ok, %Activity{id: report_id}} =
|
|
CommonAPI.report(reporter, %{
|
|
account_id: target_user.id,
|
|
comment: "I feel offended",
|
|
status_ids: [activity.id]
|
|
})
|
|
|
|
{:ok, report} = CommonAPI.update_report_state(report_id, "resolved")
|
|
|
|
assert report.data["state"] == "resolved"
|
|
|
|
[reported_user, activity_id] = report.data["object"]
|
|
|
|
assert reported_user == target_user.ap_id
|
|
assert activity_id == activity.data["id"]
|
|
end
|
|
|
|
test "does not update report state when state is unsupported" do
|
|
[reporter, target_user] = insert_pair(:user)
|
|
activity = insert(:note_activity, user: target_user)
|
|
|
|
{:ok, %Activity{id: report_id}} =
|
|
CommonAPI.report(reporter, %{
|
|
account_id: target_user.id,
|
|
comment: "I feel offended",
|
|
status_ids: [activity.id]
|
|
})
|
|
|
|
assert CommonAPI.update_report_state(report_id, "test") == {:error, "Unsupported state"}
|
|
end
|
|
|
|
test "updates state of multiple reports" do
|
|
[reporter, target_user] = insert_pair(:user)
|
|
activity = insert(:note_activity, user: target_user)
|
|
|
|
{:ok, %Activity{id: first_report_id}} =
|
|
CommonAPI.report(reporter, %{
|
|
account_id: target_user.id,
|
|
comment: "I feel offended",
|
|
status_ids: [activity.id]
|
|
})
|
|
|
|
{:ok, %Activity{id: second_report_id}} =
|
|
CommonAPI.report(reporter, %{
|
|
account_id: target_user.id,
|
|
comment: "I feel very offended!",
|
|
status_ids: [activity.id]
|
|
})
|
|
|
|
{:ok, report_ids} =
|
|
CommonAPI.update_report_state([first_report_id, second_report_id], "resolved")
|
|
|
|
first_report = Activity.get_by_id(first_report_id)
|
|
second_report = Activity.get_by_id(second_report_id)
|
|
|
|
assert report_ids -- [first_report_id, second_report_id] == []
|
|
assert first_report.data["state"] == "resolved"
|
|
assert second_report.data["state"] == "resolved"
|
|
end
|
|
end
|
|
|
|
describe "reblog muting" do
|
|
setup do
|
|
muter = insert(:user)
|
|
|
|
muted = insert(:user)
|
|
|
|
[muter: muter, muted: muted]
|
|
end
|
|
|
|
test "add a reblog mute", %{muter: muter, muted: muted} do
|
|
{:ok, _reblog_mute} = CommonAPI.hide_reblogs(muter, muted)
|
|
|
|
assert User.showing_reblogs?(muter, muted) == false
|
|
end
|
|
|
|
test "remove a reblog mute", %{muter: muter, muted: muted} do
|
|
{:ok, _reblog_mute} = CommonAPI.hide_reblogs(muter, muted)
|
|
{:ok, _reblog_mute} = CommonAPI.show_reblogs(muter, muted)
|
|
|
|
assert User.showing_reblogs?(muter, muted) == true
|
|
end
|
|
end
|
|
|
|
describe "follow/2" do
|
|
test "directly follows a non-locked local user" do
|
|
[follower, followed] = insert_pair(:user)
|
|
{:ok, follower, followed, _} = CommonAPI.follow(follower, followed)
|
|
|
|
assert User.following?(follower, followed)
|
|
end
|
|
end
|
|
|
|
describe "unfollow/2" do
|
|
test "also unsubscribes a user" do
|
|
[follower, followed] = insert_pair(:user)
|
|
{:ok, follower, followed, _} = CommonAPI.follow(follower, followed)
|
|
{:ok, _subscription} = User.subscribe(follower, followed)
|
|
|
|
assert User.subscribed_to?(follower, followed)
|
|
|
|
{:ok, follower} = CommonAPI.unfollow(follower, followed)
|
|
|
|
refute User.subscribed_to?(follower, followed)
|
|
end
|
|
|
|
test "removes a pending follow for a local user" do
|
|
follower = insert(:user)
|
|
followed = insert(:user, is_locked: true)
|
|
|
|
assert {:ok, follower, followed, %{id: _activity_id, data: %{"state" => "pending"}}} =
|
|
CommonAPI.follow(follower, followed)
|
|
|
|
assert User.get_follow_state(follower, followed) == :follow_pending
|
|
assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
|
|
assert User.get_follow_state(follower, followed) == nil
|
|
|
|
assert is_nil(Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed))
|
|
|
|
assert %{
|
|
data: %{
|
|
"type" => "Undo",
|
|
"object" => %{"type" => "Follow"}
|
|
}
|
|
} = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
|
|
end
|
|
|
|
test "cancels a pending follow for a remote user" do
|
|
follower = insert(:user)
|
|
followed = insert(:user, is_locked: true, local: false, ap_enabled: true)
|
|
|
|
assert {:ok, follower, followed, %{id: _activity_id, data: %{"state" => "pending"}}} =
|
|
CommonAPI.follow(follower, followed)
|
|
|
|
assert User.get_follow_state(follower, followed) == :follow_pending
|
|
assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
|
|
assert User.get_follow_state(follower, followed) == nil
|
|
|
|
assert is_nil(Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed))
|
|
|
|
assert %{
|
|
data: %{
|
|
"type" => "Undo",
|
|
"object" => %{"type" => "Follow"}
|
|
}
|
|
} = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
|
|
end
|
|
end
|
|
|
|
describe "accept_follow_request/2" do
|
|
test "after acceptance, it sets all existing pending follow request states to 'accept'" do
|
|
user = insert(:user, is_locked: true)
|
|
follower = insert(:user)
|
|
follower_two = insert(:user)
|
|
|
|
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, user)
|
|
{:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user)
|
|
{:ok, _, _, follow_activity_three} = CommonAPI.follow(follower_two, user)
|
|
|
|
assert follow_activity.data["state"] == "pending"
|
|
assert follow_activity_two.data["state"] == "pending"
|
|
assert follow_activity_three.data["state"] == "pending"
|
|
|
|
{:ok, _follower} = CommonAPI.accept_follow_request(follower, user)
|
|
|
|
assert Repo.get(Activity, follow_activity.id).data["state"] == "accept"
|
|
assert Repo.get(Activity, follow_activity_two.id).data["state"] == "accept"
|
|
assert Repo.get(Activity, follow_activity_three.id).data["state"] == "pending"
|
|
end
|
|
|
|
test "after rejection, it sets all existing pending follow request states to 'reject'" do
|
|
user = insert(:user, is_locked: true)
|
|
follower = insert(:user)
|
|
follower_two = insert(:user)
|
|
|
|
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, user)
|
|
{:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user)
|
|
{:ok, _, _, follow_activity_three} = CommonAPI.follow(follower_two, user)
|
|
|
|
assert follow_activity.data["state"] == "pending"
|
|
assert follow_activity_two.data["state"] == "pending"
|
|
assert follow_activity_three.data["state"] == "pending"
|
|
|
|
{:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
|
|
|
|
assert Repo.get(Activity, follow_activity.id).data["state"] == "reject"
|
|
assert Repo.get(Activity, follow_activity_two.id).data["state"] == "reject"
|
|
assert Repo.get(Activity, follow_activity_three.id).data["state"] == "pending"
|
|
end
|
|
|
|
test "doesn't create a following relationship if the corresponding follow request doesn't exist" do
|
|
user = insert(:user, is_locked: true)
|
|
not_follower = insert(:user)
|
|
CommonAPI.accept_follow_request(not_follower, user)
|
|
|
|
assert Pleroma.FollowingRelationship.following?(not_follower, user) == false
|
|
end
|
|
end
|
|
|
|
describe "vote/3" do
|
|
test "does not allow to vote twice" do
|
|
user = insert(:user)
|
|
other_user = insert(:user)
|
|
|
|
{:ok, activity} =
|
|
CommonAPI.post(user, %{
|
|
status: "Am I cute?",
|
|
poll: %{options: ["Yes", "No"], expires_in: 20}
|
|
})
|
|
|
|
object = Object.normalize(activity, fetch: false)
|
|
|
|
{:ok, _, object} = CommonAPI.vote(other_user, object, [0])
|
|
|
|
assert {:error, "Already voted"} == CommonAPI.vote(other_user, object, [1])
|
|
end
|
|
end
|
|
|
|
describe "get_user/1" do
|
|
test "gets user by ap_id" do
|
|
user = insert(:user)
|
|
assert CommonAPI.get_user(user.ap_id) == user
|
|
end
|
|
|
|
test "gets user by guessed nickname" do
|
|
user = insert(:user, ap_id: "", nickname: "mario@mushroom.kingdom")
|
|
assert CommonAPI.get_user("https://mushroom.kingdom/users/mario") == user
|
|
end
|
|
|
|
test "fallback" do
|
|
assert %User{
|
|
name: "",
|
|
ap_id: "",
|
|
nickname: "erroruser@example.com"
|
|
} = CommonAPI.get_user("")
|
|
end
|
|
end
|
|
|
|
describe "with `local` visibility" do
|
|
setup do: clear_config([:instance, :federating], true)
|
|
|
|
test "post" do
|
|
user = insert(:user)
|
|
|
|
with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
|
|
{:ok, activity} = CommonAPI.post(user, %{status: "#2hu #2HU", visibility: "local"})
|
|
|
|
assert Visibility.is_local_public?(activity)
|
|
assert_not_called(Pleroma.Web.Federator.publish(activity))
|
|
end
|
|
end
|
|
|
|
test "delete" do
|
|
user = insert(:user)
|
|
|
|
{:ok, %Activity{id: activity_id}} =
|
|
CommonAPI.post(user, %{status: "#2hu #2HU", visibility: "local"})
|
|
|
|
with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
|
|
assert {:ok, %Activity{data: %{"deleted_activity_id" => ^activity_id}} = activity} =
|
|
CommonAPI.delete(activity_id, user)
|
|
|
|
assert Visibility.is_local_public?(activity)
|
|
assert_not_called(Pleroma.Web.Federator.publish(activity))
|
|
end
|
|
end
|
|
|
|
test "repeat" do
|
|
user = insert(:user)
|
|
other_user = insert(:user)
|
|
|
|
{:ok, %Activity{id: activity_id}} =
|
|
CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
|
|
|
|
with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
|
|
assert {:ok, %Activity{data: %{"type" => "Announce"}} = activity} =
|
|
CommonAPI.repeat(activity_id, user)
|
|
|
|
assert Visibility.is_local_public?(activity)
|
|
refute called(Pleroma.Web.Federator.publish(activity))
|
|
end
|
|
end
|
|
|
|
test "unrepeat" do
|
|
user = insert(:user)
|
|
other_user = insert(:user)
|
|
|
|
{:ok, %Activity{id: activity_id}} =
|
|
CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
|
|
|
|
assert {:ok, _} = CommonAPI.repeat(activity_id, user)
|
|
|
|
with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
|
|
assert {:ok, %Activity{data: %{"type" => "Undo"}} = activity} =
|
|
CommonAPI.unrepeat(activity_id, user)
|
|
|
|
assert Visibility.is_local_public?(activity)
|
|
refute called(Pleroma.Web.Federator.publish(activity))
|
|
end
|
|
end
|
|
|
|
test "favorite" do
|
|
user = insert(:user)
|
|
other_user = insert(:user)
|
|
|
|
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
|
|
|
|
with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
|
|
assert {:ok, %Activity{data: %{"type" => "Like"}} = activity} =
|
|
CommonAPI.favorite(user, activity.id)
|
|
|
|
assert Visibility.is_local_public?(activity)
|
|
refute called(Pleroma.Web.Federator.publish(activity))
|
|
end
|
|
end
|
|
|
|
test "unfavorite" do
|
|
user = insert(:user)
|
|
other_user = insert(:user)
|
|
|
|
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
|
|
|
|
{:ok, %Activity{}} = CommonAPI.favorite(user, activity.id)
|
|
|
|
with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
|
|
assert {:ok, activity} = CommonAPI.unfavorite(activity.id, user)
|
|
assert Visibility.is_local_public?(activity)
|
|
refute called(Pleroma.Web.Federator.publish(activity))
|
|
end
|
|
end
|
|
|
|
test "react_with_emoji" do
|
|
user = insert(:user)
|
|
other_user = insert(:user)
|
|
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
|
|
|
|
with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
|
|
assert {:ok, %Activity{data: %{"type" => "EmojiReact"}} = activity} =
|
|
CommonAPI.react_with_emoji(activity.id, user, "👍")
|
|
|
|
assert Visibility.is_local_public?(activity)
|
|
refute called(Pleroma.Web.Federator.publish(activity))
|
|
end
|
|
end
|
|
|
|
test "unreact_with_emoji" do
|
|
user = insert(:user)
|
|
other_user = insert(:user)
|
|
{:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
|
|
|
|
{:ok, _reaction} = CommonAPI.react_with_emoji(activity.id, user, "👍")
|
|
|
|
with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
|
|
assert {:ok, %Activity{data: %{"type" => "Undo"}} = activity} =
|
|
CommonAPI.unreact_with_emoji(activity.id, user, "👍")
|
|
|
|
assert Visibility.is_local_public?(activity)
|
|
refute called(Pleroma.Web.Federator.publish(activity))
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "update/3" do
|
|
test "updates a post" do
|
|
user = insert(:user)
|
|
{:ok, activity} = CommonAPI.post(user, %{status: "foo1", spoiler_text: "title 1"})
|
|
|
|
{:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2"})
|
|
|
|
updated_object = Object.normalize(updated)
|
|
assert updated_object.data["content"] == "updated 2"
|
|
assert Map.get(updated_object.data, "summary", "") == ""
|
|
assert Map.has_key?(updated_object.data, "updated")
|
|
end
|
|
|
|
test "does not change visibility" do
|
|
user = insert(:user)
|
|
|
|
{:ok, activity} =
|
|
CommonAPI.post(user, %{status: "foo1", spoiler_text: "title 1", visibility: "private"})
|
|
|
|
{:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2"})
|
|
|
|
updated_object = Object.normalize(updated)
|
|
assert updated_object.data["content"] == "updated 2"
|
|
assert Map.get(updated_object.data, "summary", "") == ""
|
|
assert Visibility.get_visibility(updated_object) == "private"
|
|
assert Visibility.get_visibility(updated) == "private"
|
|
end
|
|
|
|
test "updates a post with emoji" do
|
|
[{emoji1, _}, {emoji2, _} | _] = Pleroma.Emoji.get_all()
|
|
|
|
user = insert(:user)
|
|
|
|
{:ok, activity} =
|
|
CommonAPI.post(user, %{status: "foo1", spoiler_text: "title 1 :#{emoji1}:"})
|
|
|
|
{:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2 :#{emoji2}:"})
|
|
|
|
updated_object = Object.normalize(updated)
|
|
assert updated_object.data["content"] == "updated 2 :#{emoji2}:"
|
|
assert %{^emoji2 => _} = updated_object.data["emoji"]
|
|
end
|
|
|
|
test "updates a post with emoji and federate properly" do
|
|
[{emoji1, _}, {emoji2, _} | _] = Pleroma.Emoji.get_all()
|
|
|
|
user = insert(:user)
|
|
|
|
{:ok, activity} =
|
|
CommonAPI.post(user, %{status: "foo1", spoiler_text: "title 1 :#{emoji1}:"})
|
|
|
|
clear_config([:instance, :federating], true)
|
|
|
|
with_mock Pleroma.Web.Federator,
|
|
publish: fn _p -> nil end do
|
|
{:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2 :#{emoji2}:"})
|
|
|
|
assert updated.data["object"]["content"] == "updated 2 :#{emoji2}:"
|
|
assert %{^emoji2 => _} = updated.data["object"]["emoji"]
|
|
|
|
assert called(Pleroma.Web.Federator.publish(updated))
|
|
end
|
|
end
|
|
|
|
test "editing a post that copied a remote title with remote emoji should keep that emoji" do
|
|
remote_emoji_uri = "https://remote.org/emoji.png"
|
|
|
|
note =
|
|
insert(
|
|
:note,
|
|
data: %{
|
|
"summary" => ":remoteemoji:",
|
|
"emoji" => %{
|
|
"remoteemoji" => remote_emoji_uri
|
|
},
|
|
"tag" => [
|
|
%{
|
|
"type" => "Emoji",
|
|
"name" => "remoteemoji",
|
|
"icon" => %{"url" => remote_emoji_uri}
|
|
}
|
|
]
|
|
}
|
|
)
|
|
|
|
note_activity = insert(:note_activity, note: note)
|
|
|
|
user = insert(:user)
|
|
|
|
{:ok, reply} =
|
|
CommonAPI.post(user, %{
|
|
status: "reply",
|
|
spoiler_text: ":remoteemoji:",
|
|
in_reply_to_id: note_activity.id
|
|
})
|
|
|
|
assert reply.object.data["emoji"]["remoteemoji"] == remote_emoji_uri
|
|
|
|
{:ok, edit} =
|
|
CommonAPI.update(user, reply, %{status: "reply mew mew", spoiler_text: ":remoteemoji:"})
|
|
|
|
edited_note = Pleroma.Object.normalize(edit)
|
|
|
|
assert edited_note.data["emoji"]["remoteemoji"] == remote_emoji_uri
|
|
end
|
|
|
|
test "respects MRF" do
|
|
user = insert(:user)
|
|
|
|
clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy])
|
|
clear_config([:mrf_keyword, :replace], [{"updated", "mewmew"}])
|
|
|
|
{:ok, activity} = CommonAPI.post(user, %{status: "foo1", spoiler_text: "updated 1"})
|
|
assert Object.normalize(activity).data["summary"] == "mewmew 1"
|
|
|
|
{:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2"})
|
|
|
|
updated_object = Object.normalize(updated)
|
|
assert updated_object.data["content"] == "mewmew 2"
|
|
assert Map.get(updated_object.data, "summary", "") == ""
|
|
assert Map.has_key?(updated_object.data, "updated")
|
|
end
|
|
end
|
|
end
|