[#1149] Merge remote-tracking branch 'remotes/upstream/develop' into 1149-oban-job...
authorIvan Tashkinov <ivantashkinov@gmail.com>
Fri, 6 Sep 2019 10:26:05 +0000 (13:26 +0300)
committerIvan Tashkinov <ivantashkinov@gmail.com>
Fri, 6 Sep 2019 10:26:05 +0000 (13:26 +0300)
# Conflicts:
# test/web/twitter_api/twitter_api_controller_test.exs

1  2 
CHANGELOG.md
lib/pleroma/user.ex
test/notification_test.exs
test/user_test.exs
test/web/mastodon_api/mastodon_api_controller_test.exs
test/web/twitter_api/twitter_api_test.exs

diff --combined CHANGELOG.md
index c1c966ea59e9574a07b5b92e6a62ef41c6c1e1a6,50a4467e8f069c5911cdf329db26da011ee10da7..23ac4b86665ea20d5afe46fcacefe766558146c6
@@@ -22,8 -22,6 +22,8 @@@ The format is based on [Keep a Changelo
  - AdminAPI: Add "godmode" while fetching user statuses (i.e. admin can see private statuses)
  - Improve digest email template
  – Pagination: (optional) return `total` alongside with `items` when paginating
 +- Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) and `Pleroma.Web.Federator.RetryQueue` with [Oban](https://github.com/sorentwo/oban) (see [`docs/config.md`](docs/config.md) on migrating customized worker / retry settings)
 +- Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler
  
  ### Fixed
  - Following from Osada
@@@ -34,6 -32,7 +34,7 @@@
  - `federation_incoming_replies_max_depth` option being ignored in certain cases
  - Federation/MediaProxy not working with instances that have wrong certificate order
  - Mastodon API: Handling of search timeouts (`/api/v1/search` and `/api/v2/search`)
+ - Mastodon API: Misskey's endless polls being unable to render
  - Mastodon API: Embedded relationships not being properly rendered in the Account entity of Status entity
  - Mastodon API: Notifications endpoint crashing if one notification failed to render
  - Mastodon API: follower/following counters not being nullified, when `hide_follows`/`hide_followers` is set
  - RichMedia: add the rich media ttl based on image expiration time.
  
  ### Removed
+ - GNU Social API with Qvitter extensions support
  - Emoji: Remove longfox emojis.
  - Remove `Reply-To` header from report emails for admins.
  - ActivityPub: The `accept_blocks` configuration setting.
diff --combined lib/pleroma/user.ex
index 2fe7e1748c678e601503b20c6a87499979758953,3aa245f2aa43f60389fc8a8f43023de09a39268e..0d0fbe3a859d5ae70c55256c30a50798f757642d
@@@ -27,7 -27,6 +27,7 @@@ defmodule Pleroma.User d
    alias Pleroma.Web.OStatus
    alias Pleroma.Web.RelMe
    alias Pleroma.Web.Websub
 +  alias Pleroma.Workers.BackgroundWorker
  
    require Logger
  
      end)
    end
  
-   def get_cached_by_nickname_or_id(nickname_or_id) do
-     get_cached_by_id(nickname_or_id) || get_cached_by_nickname(nickname_or_id)
+   def get_cached_by_nickname_or_id(nickname_or_id, opts \\ []) do
+     restrict_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
+     cond do
+       is_integer(nickname_or_id) or Pleroma.FlakeId.is_flake_id?(nickname_or_id) ->
+         get_cached_by_id(nickname_or_id) || get_cached_by_nickname(nickname_or_id)
+       restrict_to_local == false ->
+         get_cached_by_nickname(nickname_or_id)
+       restrict_to_local == :unauthenticated and match?(%User{}, opts[:for]) ->
+         get_cached_by_nickname(nickname_or_id)
+       true ->
+         nil
+     end
    end
  
    def get_by_nickname(nickname) do
    end
  
    @doc "Fetch some posts when the user has just been federated with"
 -  def fetch_initial_posts(user),
 -    do: PleromaJobQueue.enqueue(:background, __MODULE__, [:fetch_initial_posts, user])
 +  def fetch_initial_posts(user) do
 +    BackgroundWorker.enqueue("fetch_initial_posts", %{"user_id" => user.id})
 +  end
  
    @spec get_followers_query(User.t(), pos_integer() | nil) :: Ecto.Query.t()
    def get_followers_query(%User{} = user, nil) do
    end
  
    def deactivate_async(user, status \\ true) do
 -    PleromaJobQueue.enqueue(:background, __MODULE__, [:deactivate_async, user, status])
 +    BackgroundWorker.enqueue("deactivate_user", %{"user_id" => user.id, "status" => status})
    end
  
    def deactivate(%User{} = user, status \\ true) do
      |> update_and_set_cache()
    end
  
 -  @spec delete(User.t()) :: :ok
 -  def delete(%User{} = user),
 -    do: PleromaJobQueue.enqueue(:background, __MODULE__, [:delete, user])
 +  def delete(%User{} = user) do
 +    BackgroundWorker.enqueue("delete_user", %{"user_id" => user.id})
 +  end
  
    @spec perform(atom(), User.t()) :: {:ok, User.t()}
    def perform(:delete, %User{} = user) do
      Repo.all(query)
    end
  
 -  def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers),
 -    do:
 -      PleromaJobQueue.enqueue(:background, __MODULE__, [
 -        :blocks_import,
 -        blocker,
 -        blocked_identifiers
 -      ])
 -
 -  def follow_import(%User{} = follower, followed_identifiers) when is_list(followed_identifiers),
 -    do:
 -      PleromaJobQueue.enqueue(:background, __MODULE__, [
 -        :follow_import,
 -        follower,
 -        followed_identifiers
 -      ])
 +  def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers) do
 +    BackgroundWorker.enqueue("blocks_import", %{
 +      "blocker_id" => blocker.id,
 +      "blocked_identifiers" => blocked_identifiers
 +    })
 +  end
 +
 +  def follow_import(%User{} = follower, followed_identifiers)
 +      when is_list(followed_identifiers) do
 +    BackgroundWorker.enqueue("follow_import", %{
 +      "follower_id" => follower.id,
 +      "followed_identifiers" => followed_identifiers
 +    })
 +  end
  
    def delete_user_activities(%User{ap_id: ap_id} = user) do
      ap_id
index e1c9f4f93ba151d4587be144a1c27a16f84810af,2a52dad8d87f9a344d74a8a89c5e234cee5c6b73..3be9db09b38074e3bd2868c6eea32a559dbe8e9c
@@@ -8,12 -8,10 +8,11 @@@ defmodule Pleroma.NotificationTest d
    import Pleroma.Factory
  
    alias Pleroma.Notification
 +  alias Pleroma.Tests.ObanHelpers
    alias Pleroma.User
    alias Pleroma.Web.ActivityPub.Transmogrifier
    alias Pleroma.Web.CommonAPI
    alias Pleroma.Web.Streamer
-   alias Pleroma.Web.TwitterAPI.TwitterAPI
  
    describe "create_notifications" do
      test "notifies someone when they are directly addressed" do
@@@ -22,7 -20,7 +21,7 @@@
        third_user = insert(:user)
  
        {:ok, activity} =
-         TwitterAPI.create_status(user, %{
+         CommonAPI.post(user, %{
            "status" => "hey @#{other_user.nickname} and @#{third_user.nickname}"
          })
  
@@@ -40,7 -38,7 +39,7 @@@
  
        User.subscribe(subscriber, user)
  
-       {:ok, status} = TwitterAPI.create_status(user, %{"status" => "Akariiiin"})
+       {:ok, status} = CommonAPI.post(user, %{"status" => "Akariiiin"})
        {:ok, [notification]} = Notification.create_notifications(status)
  
        assert notification.user_id == subscriber.id
      test "it doesn't create a notification for follow-unfollow-follow chains" do
        user = insert(:user)
        followed_user = insert(:user)
-       {:ok, _, _, activity} = TwitterAPI.follow(user, %{"user_id" => followed_user.id})
+       {:ok, _, _, activity} = CommonAPI.follow(user, followed_user)
        Notification.create_notification(activity, followed_user)
-       TwitterAPI.unfollow(user, %{"user_id" => followed_user.id})
-       {:ok, _, _, activity_dupe} = TwitterAPI.follow(user, %{"user_id" => followed_user.id})
+       CommonAPI.unfollow(user, followed_user)
+       {:ok, _, _, activity_dupe} = CommonAPI.follow(user, followed_user)
        refute Notification.create_notification(activity_dupe, followed_user)
      end
  
-     test "it doesn't create a notification for like-unlike-like chains" do
-       user = insert(:user)
-       liked_user = insert(:user)
-       {:ok, status} = TwitterAPI.create_status(liked_user, %{"status" => "Yui is best yuru"})
-       {:ok, fav_status} = TwitterAPI.fav(user, status.id)
-       Notification.create_notification(fav_status, liked_user)
-       TwitterAPI.unfav(user, status.id)
-       {:ok, dupe} = TwitterAPI.fav(user, status.id)
-       refute Notification.create_notification(dupe, liked_user)
-     end
-     test "it doesn't create a notification for repeat-unrepeat-repeat chains" do
-       user = insert(:user)
-       retweeted_user = insert(:user)
-       {:ok, status} =
-         TwitterAPI.create_status(retweeted_user, %{
-           "status" => "Send dupe notifications to the shadow realm"
-         })
-       {:ok, retweeted_activity} = TwitterAPI.repeat(user, status.id)
-       Notification.create_notification(retweeted_activity, retweeted_user)
-       TwitterAPI.unrepeat(user, status.id)
-       {:ok, dupe} = TwitterAPI.repeat(user, status.id)
-       refute Notification.create_notification(dupe, retweeted_user)
-     end
      test "it doesn't create duplicate notifications for follow+subscribed users" do
        user = insert(:user)
        subscriber = insert(:user)
  
-       {:ok, _, _, _} = TwitterAPI.follow(subscriber, %{"user_id" => user.id})
+       {:ok, _, _, _} = CommonAPI.follow(subscriber, user)
        User.subscribe(subscriber, user)
-       {:ok, status} = TwitterAPI.create_status(user, %{"status" => "Akariiiin"})
+       {:ok, status} = CommonAPI.post(user, %{"status" => "Akariiiin"})
        {:ok, [_notif]} = Notification.create_notifications(status)
      end
  
  
        User.subscribe(subscriber, user)
  
-       {:ok, status} =
-         TwitterAPI.create_status(user, %{"status" => "inwisible", "visibility" => "direct"})
+       {:ok, status} = CommonAPI.post(user, %{"status" => "inwisible", "visibility" => "direct"})
  
        assert {:ok, []} == Notification.create_notifications(status)
      end
        user = insert(:user)
        other_user = insert(:user)
  
-       {:ok, activity} =
-         TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
+       {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}"})
  
        {:ok, [notification]} = Notification.create_notifications(activity)
        {:ok, notification} = Notification.get(other_user, notification.id)
        user = insert(:user)
        other_user = insert(:user)
  
-       {:ok, activity} =
-         TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
+       {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}"})
  
        {:ok, [notification]} = Notification.create_notifications(activity)
        {:error, _notification} = Notification.get(user, notification.id)
        user = insert(:user)
        other_user = insert(:user)
  
-       {:ok, activity} =
-         TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
+       {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}"})
  
        {:ok, [notification]} = Notification.create_notifications(activity)
        {:ok, notification} = Notification.dismiss(other_user, notification.id)
        user = insert(:user)
        other_user = insert(:user)
  
-       {:ok, activity} =
-         TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
+       {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{other_user.nickname}"})
  
        {:ok, [notification]} = Notification.create_notifications(activity)
        {:error, _notification} = Notification.dismiss(user, notification.id)
        third_user = insert(:user)
  
        {:ok, activity} =
-         TwitterAPI.create_status(user, %{
+         CommonAPI.post(user, %{
            "status" => "hey @#{other_user.nickname} and @#{third_user.nickname} !"
          })
  
        {:ok, _notifs} = Notification.create_notifications(activity)
  
        {:ok, activity} =
-         TwitterAPI.create_status(user, %{
+         CommonAPI.post(user, %{
            "status" => "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
          })
  
        other_user = insert(:user)
  
        {:ok, _activity} =
-         TwitterAPI.create_status(user, %{
+         CommonAPI.post(user, %{
            "status" => "hey @#{other_user.nickname}!"
          })
  
        {:ok, _activity} =
-         TwitterAPI.create_status(user, %{
+         CommonAPI.post(user, %{
            "status" => "hey again @#{other_user.nickname}!"
          })
  
        assert n2.id > n1.id
  
        {:ok, _activity} =
-         TwitterAPI.create_status(user, %{
+         CommonAPI.post(user, %{
            "status" => "hey yet again @#{other_user.nickname}!"
          })
  
  
        refute Enum.empty?(Notification.for_user(other_user))
  
 -      User.delete(user)
 +      {:ok, job} = User.delete(user)
 +      ObanHelpers.perform(job)
  
        assert Enum.empty?(Notification.for_user(other_user))
      end
        }
  
        {:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message)
 +      ObanHelpers.perform_all()
  
        assert Enum.empty?(Notification.for_user(local_user))
      end
        muted = insert(:user)
        {:ok, user} = User.mute(user, muted, false)
  
-       {:ok, _activity} = TwitterAPI.create_status(muted, %{"status" => "hey @#{user.nickname}"})
+       {:ok, _activity} = CommonAPI.post(muted, %{"status" => "hey @#{user.nickname}"})
  
        assert length(Notification.for_user(user)) == 1
      end
        muted = insert(:user)
        {:ok, user} = User.mute(user, muted)
  
-       {:ok, _activity} = TwitterAPI.create_status(muted, %{"status" => "hey @#{user.nickname}"})
+       {:ok, _activity} = CommonAPI.post(muted, %{"status" => "hey @#{user.nickname}"})
  
        assert Notification.for_user(user) == []
      end
        blocked = insert(:user)
        {:ok, user} = User.block(user, blocked)
  
-       {:ok, _activity} = TwitterAPI.create_status(blocked, %{"status" => "hey @#{user.nickname}"})
+       {:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
  
        assert Notification.for_user(user) == []
      end
        blocked = insert(:user, ap_id: "http://some-domain.com")
        {:ok, user} = User.block_domain(user, "some-domain.com")
  
-       {:ok, _activity} = TwitterAPI.create_status(blocked, %{"status" => "hey @#{user.nickname}"})
+       {:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
  
        assert Notification.for_user(user) == []
      end
        user = insert(:user)
        another_user = insert(:user)
  
-       {:ok, activity} =
-         TwitterAPI.create_status(another_user, %{"status" => "hey @#{user.nickname}"})
+       {:ok, activity} = CommonAPI.post(another_user, %{"status" => "hey @#{user.nickname}"})
  
        {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
        assert Notification.for_user(user) == []
        muted = insert(:user)
        {:ok, user} = User.mute(user, muted)
  
-       {:ok, _activity} = TwitterAPI.create_status(muted, %{"status" => "hey @#{user.nickname}"})
+       {:ok, _activity} = CommonAPI.post(muted, %{"status" => "hey @#{user.nickname}"})
  
        assert length(Notification.for_user(user, %{with_muted: true})) == 1
      end
        blocked = insert(:user)
        {:ok, user} = User.block(user, blocked)
  
-       {:ok, _activity} = TwitterAPI.create_status(blocked, %{"status" => "hey @#{user.nickname}"})
+       {:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
  
        assert length(Notification.for_user(user, %{with_muted: true})) == 1
      end
        blocked = insert(:user, ap_id: "http://some-domain.com")
        {:ok, user} = User.block_domain(user, "some-domain.com")
  
-       {:ok, _activity} = TwitterAPI.create_status(blocked, %{"status" => "hey @#{user.nickname}"})
+       {:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
  
        assert length(Notification.for_user(user, %{with_muted: true})) == 1
      end
        user = insert(:user)
        another_user = insert(:user)
  
-       {:ok, activity} =
-         TwitterAPI.create_status(another_user, %{"status" => "hey @#{user.nickname}"})
+       {:ok, activity} = CommonAPI.post(another_user, %{"status" => "hey @#{user.nickname}"})
  
        {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
        assert length(Notification.for_user(user, %{with_muted: true})) == 1
diff --combined test/user_test.exs
index 0acd0db4e69c06f2541a4b65095401edf7e1ab0b,a25b72f4ed2cdfb4cd011331434a8b6f73e4719c..695f903db43e3887c18a5c9c925c29f47dfae3ce
@@@ -7,16 -7,14 +7,16 @@@ defmodule Pleroma.UserTest d
    alias Pleroma.Builders.UserBuilder
    alias Pleroma.Object
    alias Pleroma.Repo
 +  alias Pleroma.Tests.ObanHelpers
    alias Pleroma.User
    alias Pleroma.Web.ActivityPub.ActivityPub
    alias Pleroma.Web.CommonAPI
  
    use Pleroma.DataCase
 +  use Oban.Testing, repo: Pleroma.Repo
  
 -  import Pleroma.Factory
    import Mock
 +  import Pleroma.Factory
  
    setup_all do
      Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
@@@ -71,8 -69,8 +71,8 @@@
      locked = insert(:user, %{info: %{locked: true}})
      follower = insert(:user)
  
-     Pleroma.Web.TwitterAPI.TwitterAPI.follow(follower, %{"user_id" => unlocked.id})
-     Pleroma.Web.TwitterAPI.TwitterAPI.follow(follower, %{"user_id" => locked.id})
+     CommonAPI.follow(follower, unlocked)
+     CommonAPI.follow(follower, locked)
  
      assert {:ok, []} = User.get_follow_requests(unlocked)
      assert {:ok, [activity]} = User.get_follow_requests(locked)
@@@ -85,9 -83,9 +85,9 @@@
      pending_follower = insert(:user)
      accepted_follower = insert(:user)
  
-     Pleroma.Web.TwitterAPI.TwitterAPI.follow(pending_follower, %{"user_id" => locked.id})
-     Pleroma.Web.TwitterAPI.TwitterAPI.follow(pending_follower, %{"user_id" => locked.id})
-     Pleroma.Web.TwitterAPI.TwitterAPI.follow(accepted_follower, %{"user_id" => locked.id})
+     CommonAPI.follow(pending_follower, locked)
+     CommonAPI.follow(pending_follower, locked)
+     CommonAPI.follow(accepted_follower, locked)
      User.follow(accepted_follower, locked)
  
      assert {:ok, [activity]} = User.get_follow_requests(locked)
          user3.nickname
        ]
  
 -      result = User.follow_import(user1, identifiers)
 +      {:ok, job} = User.follow_import(user1, identifiers)
 +      result = ObanHelpers.perform(job)
 +
        assert is_list(result)
        assert result == [user2, user3]
      end
          user3.nickname
        ]
  
 -      result = User.blocks_import(user1, identifiers)
 +      {:ok, job} = User.blocks_import(user1, identifiers)
 +      result = ObanHelpers.perform(job)
 +
        assert is_list(result)
        assert result == [user2, user3]
      end
      test "it deletes deactivated user" do
        {:ok, user} = insert(:user, info: %{deactivated: true}) |> User.set_cache()
  
 -      assert {:ok, _} = User.delete(user)
 +      {:ok, job} = User.delete(user)
 +      {:ok, _user} = ObanHelpers.perform(job)
 +
        refute User.get_by_id(user.id)
      end
  
        {:ok, like_two, _} = CommonAPI.favorite(activity.id, follower)
        {:ok, repeat, _} = CommonAPI.repeat(activity_two.id, user)
  
 -      {:ok, _} = User.delete(user)
 +      {:ok, job} = User.delete(user)
 +      {:ok, _user} = ObanHelpers.perform(job)
  
        follower = User.get_cached_by_id(follower.id)
  
        {:ok, follower} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
        {:ok, _} = User.follow(follower, user)
  
 -      {:ok, _user} = User.delete(user)
 -
 -      assert called(
 -               Pleroma.Web.ActivityPub.Publisher.publish_one(%{
 -                 inbox: "http://mastodon.example.org/inbox"
 -               })
 +      {:ok, job} = User.delete(user)
 +      {:ok, _user} = ObanHelpers.perform(job)
 +
 +      assert ObanHelpers.member?(
 +               %{
 +                 "op" => "publish_one",
 +                 "params" => %{
 +                   "inbox" => "http://mastodon.example.org/inbox",
 +                   "id" => "pleroma:fakeid"
 +                 }
 +               },
 +               all_enqueued(worker: Pleroma.Workers.PublisherWorker)
               )
      end
    end
      test "User.delete() plugs any possible zombie objects" do
        user = insert(:user)
  
 -      {:ok, _} = User.delete(user)
 +      {:ok, job} = User.delete(user)
 +      {:ok, _} = ObanHelpers.perform(job)
  
        {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
  
      {:ok, _follower2} = User.follow(follower2, user)
      {:ok, _follower3} = User.follow(follower3, user)
  
-     {:ok, _} = User.block(user, follower)
+     {:ok, user} = User.block(user, follower)
  
-     user_show = Pleroma.Web.TwitterAPI.UserView.render("show.json", %{user: user})
-     assert Map.get(user_show, "followers_count") == 2
+     assert User.user_info(user).follower_count == 2
    end
  
    describe "list_inactive_users_query/1" do
          to = Enum.random(users -- [user])
  
          {:ok, _} =
-           Pleroma.Web.TwitterAPI.TwitterAPI.create_status(user, %{
+           CommonAPI.post(user, %{
              "status" => "hey @#{to.nickname}"
            })
        end)
  
        Enum.each(recipients, fn to ->
          {:ok, _} =
-           Pleroma.Web.TwitterAPI.TwitterAPI.create_status(sender, %{
+           CommonAPI.post(sender, %{
              "status" => "hey @#{to.nickname}"
            })
  
          {:ok, _} =
-           Pleroma.Web.TwitterAPI.TwitterAPI.create_status(sender, %{
+           CommonAPI.post(sender, %{
              "status" => "hey again @#{to.nickname}"
            })
        end)
index 64b889d55c2be8bbfa08b86a70aa41eb033cd537,e18f8f0d1df842035d08ab14f8738204c07adab2..9269e1e09242420a35693533a525b2d1097f1040
@@@ -13,7 -13,6 +13,7 @@@ defmodule Pleroma.Web.MastodonAPI.Masto
    alias Pleroma.Object
    alias Pleroma.Repo
    alias Pleroma.ScheduledActivity
 +  alias Pleroma.Tests.ObanHelpers
    alias Pleroma.User
    alias Pleroma.Web.ActivityPub.ActivityPub
    alias Pleroma.Web.CommonAPI
@@@ -22,7 -21,6 +22,6 @@@
    alias Pleroma.Web.OAuth.Token
    alias Pleroma.Web.OStatus
    alias Pleroma.Web.Push
-   alias Pleroma.Web.TwitterAPI.TwitterAPI
    import Pleroma.Factory
    import ExUnit.CaptureLog
    import Tesla.Mock
          filename: "an_image.jpg"
        }
  
-       media =
-         TwitterAPI.upload(file, user, "json")
-         |> Jason.decode!()
+       {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: user.ap_id)
  
-       {:ok, image_post} =
-         CommonAPI.post(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
+       {:ok, image_post} = CommonAPI.post(user, %{"status" => "cofe", "media_ids" => [media_id]})
  
        conn =
          conn
      end
    end
  
-   test "account fetching", %{conn: conn} do
-     user = insert(:user)
+   describe "account fetching" do
+     test "works by id" do
+       user = insert(:user)
  
-     conn =
-       conn
-       |> get("/api/v1/accounts/#{user.id}")
+       conn =
+         build_conn()
+         |> get("/api/v1/accounts/#{user.id}")
  
-     assert %{"id" => id} = json_response(conn, 200)
-     assert id == to_string(user.id)
+       assert %{"id" => id} = json_response(conn, 200)
+       assert id == to_string(user.id)
  
-     conn =
-       build_conn()
-       |> get("/api/v1/accounts/-1")
+       conn =
+         build_conn()
+         |> get("/api/v1/accounts/-1")
  
-     assert %{"error" => "Can't find user"} = json_response(conn, 404)
-   end
+       assert %{"error" => "Can't find user"} = json_response(conn, 404)
+     end
  
-   test "account fetching also works nickname", %{conn: conn} do
-     user = insert(:user)
+     test "works by nickname" do
+       user = insert(:user)
  
-     conn =
-       conn
-       |> get("/api/v1/accounts/#{user.nickname}")
+       conn =
+         build_conn()
+         |> get("/api/v1/accounts/#{user.nickname}")
  
-     assert %{"id" => id} = json_response(conn, 200)
-     assert id == user.id
+       assert %{"id" => id} = json_response(conn, 200)
+       assert id == user.id
+     end
+     test "works by nickname for remote users" do
+       limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
+       Pleroma.Config.put([:instance, :limit_to_local_content], false)
+       user = insert(:user, nickname: "user@example.com", local: false)
+       conn =
+         build_conn()
+         |> get("/api/v1/accounts/#{user.nickname}")
+       Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
+       assert %{"id" => id} = json_response(conn, 200)
+       assert id == user.id
+     end
+     test "respects limit_to_local_content == :all for remote user nicknames" do
+       limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
+       Pleroma.Config.put([:instance, :limit_to_local_content], :all)
+       user = insert(:user, nickname: "user@example.com", local: false)
+       conn =
+         build_conn()
+         |> get("/api/v1/accounts/#{user.nickname}")
+       Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
+       assert json_response(conn, 404)
+     end
+     test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do
+       limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content])
+       Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
+       user = insert(:user, nickname: "user@example.com", local: false)
+       reading_user = insert(:user)
+       conn =
+         build_conn()
+         |> get("/api/v1/accounts/#{user.nickname}")
+       assert json_response(conn, 404)
+       conn =
+         build_conn()
+         |> assign(:user, reading_user)
+         |> get("/api/v1/accounts/#{user.nickname}")
+       Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local)
+       assert %{"id" => id} = json_response(conn, 200)
+       assert id == user.id
+     end
    end
  
    test "mascot upload", %{conn: conn} do
      end
  
      test "it sends an email to user", %{user: user} do
 +      ObanHelpers.perform_all()
        token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
  
        email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
        |> post("/api/v1/pleroma/accounts/confirmation_resend?email=#{user.email}")
        |> json_response(:no_content)
  
 +      ObanHelpers.perform_all()
 +
        email = Pleroma.Emails.UserEmail.account_confirmation_email(user)
        notify_email = Config.get([:instance, :notify_email])
        instance_name = Config.get([:instance, :name])
index bf063a0dec5307d93a750c89427d4155a5b5661d,c5b18234e092a7a7a6f335497d786411f2bbe457..3c0528776d669f22915be26e6ea65c2ec2457539
  
  defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
    use Pleroma.DataCase
-   alias Pleroma.Activity
-   alias Pleroma.Object
    alias Pleroma.Repo
 +  alias Pleroma.Tests.ObanHelpers
    alias Pleroma.User
    alias Pleroma.UserInviteToken
-   alias Pleroma.Web.ActivityPub.ActivityPub
-   alias Pleroma.Web.TwitterAPI.ActivityView
+   alias Pleroma.Web.MastodonAPI.AccountView
    alias Pleroma.Web.TwitterAPI.TwitterAPI
-   alias Pleroma.Web.TwitterAPI.UserView
-   import Pleroma.Factory
  
    setup_all do
      Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
      :ok
    end
  
-   test "create a status" do
-     user = insert(:user)
-     mentioned_user = insert(:user, %{nickname: "shp", ap_id: "shp"})
-     object_data = %{
-       "type" => "Image",
-       "url" => [
-         %{
-           "type" => "Link",
-           "mediaType" => "image/jpg",
-           "href" => "http://example.org/image.jpg"
-         }
-       ],
-       "uuid" => 1
-     }
-     object = Repo.insert!(%Object{data: object_data})
-     input = %{
-       "status" =>
-         "Hello again, @shp.<script></script>\nThis is on another :firefox: line. #2hu #epic #phantasmagoric",
-       "media_ids" => [object.id]
-     }
-     {:ok, activity = %Activity{}} = TwitterAPI.create_status(user, input)
-     object = Object.normalize(activity)
-     expected_text =
-       "Hello again, <span class='h-card'><a data-user='#{mentioned_user.id}' class='u-url mention' href='shp'>@<span>shp</span></a></span>.&lt;script&gt;&lt;/script&gt;<br>This is on another :firefox: line. <a class='hashtag' data-tag='2hu' href='http://localhost:4001/tag/2hu' rel='tag'>#2hu</a> <a class='hashtag' data-tag='epic' href='http://localhost:4001/tag/epic' rel='tag'>#epic</a> <a class='hashtag' data-tag='phantasmagoric' href='http://localhost:4001/tag/phantasmagoric' rel='tag'>#phantasmagoric</a><br><a href=\"http://example.org/image.jpg\" class='attachment'>image.jpg</a>"
-     assert get_in(object.data, ["content"]) == expected_text
-     assert get_in(object.data, ["type"]) == "Note"
-     assert get_in(object.data, ["actor"]) == user.ap_id
-     assert get_in(activity.data, ["actor"]) == user.ap_id
-     assert Enum.member?(get_in(activity.data, ["cc"]), User.ap_followers(user))
-     assert Enum.member?(
-              get_in(activity.data, ["to"]),
-              "https://www.w3.org/ns/activitystreams#Public"
-            )
-     assert Enum.member?(get_in(activity.data, ["to"]), "shp")
-     assert activity.local == true
-     assert %{"firefox" => "http://localhost:4001/emoji/Firefox.gif"} = object.data["emoji"]
-     # hashtags
-     assert object.data["tag"] == ["2hu", "epic", "phantasmagoric"]
-     # Add a context
-     assert is_binary(get_in(activity.data, ["context"]))
-     assert is_binary(get_in(object.data, ["context"]))
-     assert is_list(object.data["attachment"])
-     assert activity.data["object"] == object.data["id"]
-     user = User.get_cached_by_ap_id(user.ap_id)
-     assert user.info.note_count == 1
-   end
-   test "create a status that is a reply" do
-     user = insert(:user)
-     input = %{
-       "status" => "Hello again."
-     }
-     {:ok, activity = %Activity{}} = TwitterAPI.create_status(user, input)
-     object = Object.normalize(activity)
-     input = %{
-       "status" => "Here's your (you).",
-       "in_reply_to_status_id" => activity.id
-     }
-     {:ok, reply = %Activity{}} = TwitterAPI.create_status(user, input)
-     reply_object = Object.normalize(reply)
-     assert get_in(reply.data, ["context"]) == get_in(activity.data, ["context"])
-     assert get_in(reply_object.data, ["context"]) == get_in(object.data, ["context"])
-     assert get_in(reply_object.data, ["inReplyTo"]) == get_in(activity.data, ["object"])
-     assert Activity.get_in_reply_to_activity(reply).id == activity.id
-   end
-   test "Follow another user using user_id" do
-     user = insert(:user)
-     followed = insert(:user)
-     {:ok, user, followed, _activity} = TwitterAPI.follow(user, %{"user_id" => followed.id})
-     assert User.ap_followers(followed) in user.following
-     {:ok, _, _, _} = TwitterAPI.follow(user, %{"user_id" => followed.id})
-   end
-   test "Follow another user using screen_name" do
-     user = insert(:user)
-     followed = insert(:user)
-     {:ok, user, followed, _activity} =
-       TwitterAPI.follow(user, %{"screen_name" => followed.nickname})
-     assert User.ap_followers(followed) in user.following
-     followed = User.get_cached_by_ap_id(followed.ap_id)
-     assert followed.info.follower_count == 1
-     {:ok, _, _, _} = TwitterAPI.follow(user, %{"screen_name" => followed.nickname})
-   end
-   test "Unfollow another user using user_id" do
-     unfollowed = insert(:user)
-     user = insert(:user, %{following: [User.ap_followers(unfollowed)]})
-     ActivityPub.follow(user, unfollowed)
-     {:ok, user, unfollowed} = TwitterAPI.unfollow(user, %{"user_id" => unfollowed.id})
-     assert user.following == []
-     {:error, msg} = TwitterAPI.unfollow(user, %{"user_id" => unfollowed.id})
-     assert msg == "Not subscribed!"
-   end
-   test "Unfollow another user using screen_name" do
-     unfollowed = insert(:user)
-     user = insert(:user, %{following: [User.ap_followers(unfollowed)]})
-     ActivityPub.follow(user, unfollowed)
-     {:ok, user, unfollowed} = TwitterAPI.unfollow(user, %{"screen_name" => unfollowed.nickname})
-     assert user.following == []
-     {:error, msg} = TwitterAPI.unfollow(user, %{"screen_name" => unfollowed.nickname})
-     assert msg == "Not subscribed!"
-   end
-   test "Block another user using user_id" do
-     user = insert(:user)
-     blocked = insert(:user)
-     {:ok, user, blocked} = TwitterAPI.block(user, %{"user_id" => blocked.id})
-     assert User.blocks?(user, blocked)
-   end
-   test "Block another user using screen_name" do
-     user = insert(:user)
-     blocked = insert(:user)
-     {:ok, user, blocked} = TwitterAPI.block(user, %{"screen_name" => blocked.nickname})
-     assert User.blocks?(user, blocked)
-   end
-   test "Unblock another user using user_id" do
-     unblocked = insert(:user)
-     user = insert(:user)
-     {:ok, user, _unblocked} = TwitterAPI.block(user, %{"user_id" => unblocked.id})
-     {:ok, user, _unblocked} = TwitterAPI.unblock(user, %{"user_id" => unblocked.id})
-     assert user.info.blocks == []
-   end
-   test "Unblock another user using screen_name" do
-     unblocked = insert(:user)
-     user = insert(:user)
-     {:ok, user, _unblocked} = TwitterAPI.block(user, %{"screen_name" => unblocked.nickname})
-     {:ok, user, _unblocked} = TwitterAPI.unblock(user, %{"screen_name" => unblocked.nickname})
-     assert user.info.blocks == []
-   end
-   test "upload a file" do
-     user = insert(:user)
-     file = %Plug.Upload{
-       content_type: "image/jpg",
-       path: Path.absname("test/fixtures/image.jpg"),
-       filename: "an_image.jpg"
-     }
-     response = TwitterAPI.upload(file, user)
-     assert is_binary(response)
-   end
-   test "it favorites a status, returns the updated activity" do
-     user = insert(:user)
-     other_user = insert(:user)
-     note_activity = insert(:note_activity)
-     {:ok, status} = TwitterAPI.fav(user, note_activity.id)
-     updated_activity = Activity.get_by_ap_id(note_activity.data["id"])
-     assert ActivityView.render("activity.json", %{activity: updated_activity})["fave_num"] == 1
-     object = Object.normalize(note_activity)
-     assert object.data["like_count"] == 1
-     assert status == updated_activity
-     {:ok, _status} = TwitterAPI.fav(other_user, note_activity.id)
-     object = Object.normalize(note_activity)
-     assert object.data["like_count"] == 2
-     updated_activity = Activity.get_by_ap_id(note_activity.data["id"])
-     assert ActivityView.render("activity.json", %{activity: updated_activity})["fave_num"] == 2
-   end
-   test "it unfavorites a status, returns the updated activity" do
-     user = insert(:user)
-     note_activity = insert(:note_activity)
-     object = Object.normalize(note_activity)
-     {:ok, _like_activity, _object} = ActivityPub.like(user, object)
-     updated_activity = Activity.get_by_ap_id(note_activity.data["id"])
-     assert ActivityView.render("activity.json", activity: updated_activity)["fave_num"] == 1
-     {:ok, activity} = TwitterAPI.unfav(user, note_activity.id)
-     assert ActivityView.render("activity.json", activity: activity)["fave_num"] == 0
-   end
-   test "it retweets a status and returns the retweet" do
-     user = insert(:user)
-     note_activity = insert(:note_activity)
-     {:ok, status} = TwitterAPI.repeat(user, note_activity.id)
-     updated_activity = Activity.get_by_ap_id(note_activity.data["id"])
-     assert status == updated_activity
-   end
-   test "it unretweets an already retweeted status" do
-     user = insert(:user)
-     note_activity = insert(:note_activity)
-     {:ok, _status} = TwitterAPI.repeat(user, note_activity.id)
-     {:ok, status} = TwitterAPI.unrepeat(user, note_activity.id)
-     updated_activity = Activity.get_by_ap_id(note_activity.data["id"])
-     assert status == updated_activity
-   end
    test "it registers a new user and returns the user." do
      data = %{
        "nickname" => "lain",
  
      fetched_user = User.get_cached_by_nickname("lain")
  
-     assert UserView.render("show.json", %{user: user}) ==
-              UserView.render("show.json", %{user: fetched_user})
+     assert AccountView.render("account.json", %{user: user}) ==
+              AccountView.render("account.json", %{user: fetched_user})
    end
  
    test "it registers a new user with empty string in bio and returns the user." do
  
      fetched_user = User.get_cached_by_nickname("lain")
  
-     assert UserView.render("show.json", %{user: user}) ==
-              UserView.render("show.json", %{user: fetched_user})
+     assert AccountView.render("account.json", %{user: user}) ==
+              AccountView.render("account.json", %{user: fetched_user})
    end
  
    test "it sends confirmation email if :account_activation_required is specified in instance config" do
      }
  
      {:ok, user} = TwitterAPI.register_user(data)
 +    ObanHelpers.perform_all()
  
      assert user.info.confirmation_pending
  
  
        assert invite.used == true
  
-       assert UserView.render("show.json", %{user: user}) ==
-                UserView.render("show.json", %{user: fetched_user})
+       assert AccountView.render("account.json", %{user: user}) ==
+                AccountView.render("account.json", %{user: fetched_user})
      end
  
      test "returns error on invalid token" do
          {:ok, user} = TwitterAPI.register_user(data)
          fetched_user = User.get_cached_by_nickname("vinny")
  
-         assert UserView.render("show.json", %{user: user}) ==
-                  UserView.render("show.json", %{user: fetched_user})
+         assert AccountView.render("account.json", %{user: user}) ==
+                  AccountView.render("account.json", %{user: fetched_user})
        end
  
        {:ok, data: data, check_fn: check_fn}
  
        assert invite.used == true
  
-       assert UserView.render("show.json", %{user: user}) ==
-                UserView.render("show.json", %{user: fetched_user})
+       assert AccountView.render("account.json", %{user: user}) ==
+                AccountView.render("account.json", %{user: fetched_user})
  
        data = %{
          "nickname" => "GrimReaper",
  
        refute invite.used
  
-       assert UserView.render("show.json", %{user: user}) ==
-                UserView.render("show.json", %{user: fetched_user})
+       assert AccountView.render("account.json", %{user: user}) ==
+                AccountView.render("account.json", %{user: fetched_user})
      end
  
      test "error after max uses" do
        invite = Repo.get_by(UserInviteToken, token: invite.token)
        assert invite.used == true
  
-       assert UserView.render("show.json", %{user: user}) ==
-                UserView.render("show.json", %{user: fetched_user})
+       assert AccountView.render("account.json", %{user: user}) ==
+                AccountView.render("account.json", %{user: fetched_user})
  
        data = %{
          "nickname" => "GrimReaper",
      refute User.get_cached_by_nickname("lain")
    end
  
-   test "it assigns an integer conversation_id" do
-     note_activity = insert(:note_activity)
-     status = ActivityView.render("activity.json", activity: note_activity)
-     assert is_number(status["statusnet_conversation_id"])
-   end
    setup do
      Supervisor.terminate_child(Pleroma.Supervisor, Cachex)
      Supervisor.restart_child(Pleroma.Supervisor, Cachex)
      :ok
    end
-   describe "fetching a user by uri" do
-     test "fetches a user by uri" do
-       id = "https://mastodon.social/users/lambadalambda"
-       user = insert(:user)
-       {:ok, represented} = TwitterAPI.get_external_profile(user, id)
-       remote = User.get_cached_by_ap_id(id)
-       assert represented["id"] == UserView.render("show.json", %{user: remote, for: user})["id"]
-       # Also fetches the feed.
-       # assert Activity.get_create_by_object_ap_id("tag:mastodon.social,2017-04-05:objectId=1641750:objectType=Status")
-       # credo:disable-for-previous-line Credo.Check.Readability.MaxLineLength
-     end
-   end
  end