Merge branch 'feature/ci-registry' into 'develop'
authorlain <lain@soykaf.club>
Mon, 13 Jan 2020 15:25:41 +0000 (15:25 +0000)
committerlain <lain@soykaf.club>
Mon, 13 Jan 2020 15:25:41 +0000 (15:25 +0000)
Update Dockerfile with labels. Update gitlab-ci for registry usage

See merge request pleroma/pleroma!2098

31 files changed:
CHANGELOG.md
config/benchmark.exs
config/config.exs
config/description.exs
docs/API/differences_in_mastoapi_responses.md
lib/pleroma/conversation/participation.ex
lib/pleroma/object.ex
lib/pleroma/uploaders/local.ex
lib/pleroma/uploaders/mdii.ex [deleted file]
lib/pleroma/uploaders/s3.ex
lib/pleroma/uploaders/uploader.ex
lib/pleroma/web/activity_pub/publisher.ex
lib/pleroma/web/metadata/utils.ex
lib/pleroma/web/router.ex
lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex [new file with mode: 0644]
lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex [new file with mode: 0644]
lib/pleroma/web/templates/twitter_api/remote_follow/followed.html.eex [moved from lib/pleroma/web/templates/twitter_api/util/followed.html.eex with 100% similarity]
lib/pleroma/web/templates/twitter_api/util/follow.html.eex [deleted file]
lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex [deleted file]
lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex [new file with mode: 0644]
lib/pleroma/web/twitter_api/controllers/util_controller.ex
lib/pleroma/web/twitter_api/views/remote_follow_view.ex [new file with mode: 0644]
test/conversation/participation_test.exs
test/object_test.exs
test/uploaders/local_test.exs
test/uploaders/mdii_test.exs [deleted file]
test/uploaders/s3_test.exs
test/web/activity_pub/publisher_test.exs
test/web/metadata/utils_test.exs [new file with mode: 0644]
test/web/twitter_api/remote_follow_controller_test.exs [new file with mode: 0644]
test/web/twitter_api/util_controller_test.exs

index 22f199b3d14f4614b3e8f79f8e8ae459dcd604fd..39734830460c238dd70e685f1fa4cc92760bc7f9 100644 (file)
@@ -7,8 +7,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 ### Removed
 - **Breaking**: Removed 1.0+ deprecated configurations `Pleroma.Upload, :strip_exif` and `:instance, :dedupe_media`
 - **Breaking**: OStatus protocol support
+- **Breaking**: MDII uploader
 
 ### Changed
+- **Breaking:** attachments are removed along with statuses when there are no other references to it
 - **Breaking:** Elixir >=1.8 is now required (was >= 1.7)
 - **Breaking:** attachment links (`config :pleroma, :instance, no_attachment_links` and `config :pleroma, Pleroma.Upload, link_name`) disabled by default
 - 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)
@@ -104,6 +106,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - Mastodon API: Inability to get some local users by nickname in `/api/v1/accounts/:id_or_nickname`
 - AdminAPI: If some status received reports both in the "new" format and "old" format it was considered reports on two different statuses (in the context of grouped reports)
 - Admin API: Error when trying to update reports in the "old" format
+- Mastodon API: Marking a conversation as read (`POST /api/v1/conversations/:id/read`) now no longer brings it to the top in the user's direct conversation list
 </details>
 
 ## [1.1.6] - 2019-11-19
index dd99cf5fd81e9ac11de7a7a81d8f07db4b9edb6c..84c6782a298d985e59c5d3d118233b86aea12dbd 100644 (file)
@@ -82,3 +82,11 @@ config :pleroma, :database, rum_enabled: rum_enabled
 IO.puts("RUM enabled: #{rum_enabled}")
 
 config :pleroma, Pleroma.ReverseProxy.Client, Pleroma.ReverseProxy.ClientMock
+
+if File.exists?("./config/benchmark.secret.exs") do
+  import_config "benchmark.secret.exs"
+else
+  IO.puts(
+    "You may want to create benchmark.secret.exs to declare custom database connection parameters."
+  )
+end
index 103361b297373e3f5f397d00d54ced636e95c633..d41abf09099447de593135de309f35840fb9038d 100644 (file)
@@ -108,10 +108,6 @@ config :pleroma, Pleroma.Uploaders.S3,
   streaming_enabled: true,
   public_endpoint: "https://s3.amazonaws.com"
 
-config :pleroma, Pleroma.Uploaders.MDII,
-  cgi: "https://mdii.sakura.ne.jp/mdii-post.cgi",
-  files: "https://mdii.sakura.ne.jp"
-
 config :pleroma, :emoji,
   shortcode_globs: ["/emoji/custom/**/*.png"],
   pack_extensions: [".png", ".gif"],
index 45e4b43f16c3b34022aa1a517d5e9a0309d7cb9c..1089fd86c5536cbd0b2e632b9d4a529cb9046030 100644 (file)
@@ -2557,23 +2557,6 @@ config :pleroma, :config_description, [
       }
     ]
   },
-  %{
-    group: :pleroma,
-    key: Pleroma.Uploaders.MDII,
-    type: :group,
-    children: [
-      %{
-        key: :cgi,
-        type: :string,
-        suggestions: ["https://mdii.sakura.ne.jp/mdii-post.cgi"]
-      },
-      %{
-        key: :files,
-        type: :string,
-        suggestions: ["https://mdii.sakura.ne.jp"]
-      }
-    ]
-  },
   %{
     group: :pleroma,
     key: :http,
index 7f5d7681dff158b931af6a0cb1721cd6b37d0c84..bb62ed5f21b58a1e92a08c72f271fadc0e604538 100644 (file)
@@ -46,7 +46,7 @@ The `id` parameter can also be the `nickname` of the user. This only works in th
 Has these additional fields under the `pleroma` object:
 
 - `tags`: Lists an array of tags for the user
-- `relationship{}`: Includes fields as documented for Mastodon API https://docs.joinmastodon.org/api/entities/#relationship
+- `relationship{}`: Includes fields as documented for Mastodon API https://docs.joinmastodon.org/entities/relationship/
 - `is_moderator`: boolean, nullable,  true if user is a moderator
 - `is_admin`: boolean, nullable, true if user is an admin
 - `confirmation_pending`: boolean, true if a new user account is waiting on email confirmation to be activated
index aafe572803f0b99f848c146f50a931c39b4eb447..e5d28ebffdfc786480fc417ff409d116044f76bd 100644 (file)
@@ -64,11 +64,13 @@ defmodule Pleroma.Conversation.Participation do
   end
 
   def mark_as_read(participation) do
-    participation
-    |> read_cng(%{read: true})
-    |> Repo.update()
+    __MODULE__
+    |> where(id: ^participation.id)
+    |> update(set: [read: true])
+    |> select([p], p)
+    |> Repo.update_all([])
     |> case do
-      {:ok, participation} ->
+      {1, [participation]} ->
         participation = Repo.preload(participation, :user)
         User.set_unread_conversation_count(participation.user)
         {:ok, participation}
index eb37b95a6ed88da494ee69adc64bb2e4b7112e23..2452a7389345af649730392804dde6ecf2e13942 100644 (file)
@@ -17,6 +17,8 @@ defmodule Pleroma.Object do
 
   require Logger
 
+  @type t() :: %__MODULE__{}
+
   schema "objects" do
     field(:data, :map)
 
@@ -79,6 +81,20 @@ defmodule Pleroma.Object do
     Repo.one(from(object in Object, where: fragment("(?)->>'id' = ?", object.data, ^ap_id)))
   end
 
+  @doc """
+  Get a single attachment by it's name and href
+  """
+  @spec get_attachment_by_name_and_href(String.t(), String.t()) :: Object.t() | nil
+  def get_attachment_by_name_and_href(name, href) do
+    query =
+      from(o in Object,
+        where: fragment("(?)->>'name' = ?", o.data, ^name),
+        where: fragment("(?)->>'href' = ?", o.data, ^href)
+      )
+
+    Repo.one(query)
+  end
+
   defp warn_on_no_object_preloaded(ap_id) do
     "Object.normalize() called without preloaded object (#{inspect(ap_id)}). Consider preloading the object"
     |> Logger.debug()
@@ -164,6 +180,7 @@ defmodule Pleroma.Object do
 
   def delete(%Object{data: %{"id" => id}} = object) do
     with {:ok, _obj} = swap_object_with_tombstone(object),
+         :ok <- delete_attachments(object),
          deleted_activity = Activity.delete_all_by_object_ap_id(id),
          {:ok, true} <- Cachex.del(:object_cache, "object:#{id}"),
          {:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path) do
@@ -171,6 +188,77 @@ defmodule Pleroma.Object do
     end
   end
 
+  defp delete_attachments(%{data: %{"attachment" => [_ | _] = attachments, "actor" => actor}}) do
+    hrefs =
+      Enum.flat_map(attachments, fn attachment ->
+        Enum.map(attachment["url"], & &1["href"])
+      end)
+
+    names = Enum.map(attachments, & &1["name"])
+
+    uploader = Pleroma.Config.get([Pleroma.Upload, :uploader])
+
+    # find all objects for copies of the attachments, name and actor doesn't matter here
+    delete_ids =
+      from(o in Object,
+        where:
+          fragment(
+            "to_jsonb(array(select jsonb_array_elements((?)#>'{url}') ->> 'href'))::jsonb \\?| (?)",
+            o.data,
+            ^hrefs
+          )
+      )
+      |> Repo.all()
+      # we should delete 1 object for any given attachment, but don't delete files if
+      # there are more than 1 object for it
+      |> Enum.reduce(%{}, fn %{
+                               id: id,
+                               data: %{
+                                 "url" => [%{"href" => href}],
+                                 "actor" => obj_actor,
+                                 "name" => name
+                               }
+                             },
+                             acc ->
+        Map.update(acc, href, %{id: id, count: 1}, fn val ->
+          case obj_actor == actor and name in names do
+            true ->
+              # set id of the actor's object that will be deleted
+              %{val | id: id, count: val.count + 1}
+
+            false ->
+              # another actor's object, just increase count to not delete file
+              %{val | count: val.count + 1}
+          end
+        end)
+      end)
+      |> Enum.map(fn {href, %{id: id, count: count}} ->
+        # only delete files that have single instance
+        with 1 <- count do
+          prefix =
+            case Pleroma.Config.get([Pleroma.Upload, :base_url]) do
+              nil -> "media"
+              _ -> ""
+            end
+
+          base_url = Pleroma.Config.get([__MODULE__, :base_url], Pleroma.Web.base_url())
+
+          file_path = String.trim_leading(href, "#{base_url}/#{prefix}")
+
+          uploader.delete_file(file_path)
+        end
+
+        id
+      end)
+
+    from(o in Object, where: o.id in ^delete_ids)
+    |> Repo.delete_all()
+
+    :ok
+  end
+
+  defp delete_attachments(%{data: _data}), do: :ok
+
   def prune(%Object{data: %{"id" => id}} = object) do
     with {:ok, object} <- Repo.delete(object),
          {:ok, true} <- Cachex.del(:object_cache, "object:#{id}"),
index 36b3c35ecdbbb48b4df021d3bdb7ce1d0d72a27e..2e6fe32921ebe8eb25c6109033f9392c270d23f1 100644 (file)
@@ -5,10 +5,12 @@
 defmodule Pleroma.Uploaders.Local do
   @behaviour Pleroma.Uploaders.Uploader
 
+  @impl true
   def get_file(_) do
     {:ok, {:static_dir, upload_path()}}
   end
 
+  @impl true
   def put_file(upload) do
     {local_path, file} =
       case Enum.reverse(Path.split(upload.path)) do
@@ -33,4 +35,15 @@ defmodule Pleroma.Uploaders.Local do
   def upload_path do
     Pleroma.Config.get!([__MODULE__, :uploads])
   end
+
+  @impl true
+  def delete_file(path) do
+    upload_path()
+    |> Path.join(path)
+    |> File.rm()
+    |> case do
+      :ok -> :ok
+      {:error, posix_error} -> {:error, to_string(posix_error)}
+    end
+  end
 end
diff --git a/lib/pleroma/uploaders/mdii.ex b/lib/pleroma/uploaders/mdii.ex
deleted file mode 100644 (file)
index c36f3d6..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Uploaders.MDII do
-  @moduledoc "Represents uploader for https://github.com/hakaba-hitoyo/minimal-digital-image-infrastructure"
-
-  alias Pleroma.Config
-  alias Pleroma.HTTP
-
-  @behaviour Pleroma.Uploaders.Uploader
-
-  # MDII-hosted images are never passed through the MediaPlug; only local media.
-  # Delegate to Pleroma.Uploaders.Local
-  def get_file(file) do
-    Pleroma.Uploaders.Local.get_file(file)
-  end
-
-  def put_file(upload) do
-    cgi = Config.get([Pleroma.Uploaders.MDII, :cgi])
-    files = Config.get([Pleroma.Uploaders.MDII, :files])
-
-    {:ok, file_data} = File.read(upload.tempfile)
-
-    extension = String.split(upload.name, ".") |> List.last()
-    query = "#{cgi}?#{extension}"
-
-    with {:ok, %{status: 200, body: body}} <-
-           HTTP.post(query, file_data, [], adapter: [pool: :default]) do
-      remote_file_name = String.split(body) |> List.first()
-      public_url = "#{files}/#{remote_file_name}.#{extension}"
-      {:ok, {:url, public_url}}
-    else
-      _ -> Pleroma.Uploaders.Local.put_file(upload)
-    end
-  end
-end
index 9876b639806b2d000b277ba21f93d4db0cca3820..feb89cea6431f5e960a418ca6f8244ba9fde6890 100644 (file)
@@ -10,6 +10,7 @@ defmodule Pleroma.Uploaders.S3 do
 
   # The file name is re-encoded with S3's constraints here to comply with previous
   # links with less strict filenames
+  @impl true
   def get_file(file) do
     config = Config.get([__MODULE__])
     bucket = Keyword.fetch!(config, :bucket)
@@ -35,6 +36,7 @@ defmodule Pleroma.Uploaders.S3 do
       ])}}
   end
 
+  @impl true
   def put_file(%Pleroma.Upload{} = upload) do
     config = Config.get([__MODULE__])
     bucket = Keyword.get(config, :bucket)
@@ -69,6 +71,18 @@ defmodule Pleroma.Uploaders.S3 do
     end
   end
 
+  @impl true
+  def delete_file(file) do
+    [__MODULE__, :bucket]
+    |> Config.get()
+    |> ExAws.S3.delete_object(file)
+    |> ExAws.request()
+    |> case do
+      {:ok, %{status_code: 204}} -> :ok
+      error -> {:error, inspect(error)}
+    end
+  end
+
   @regex Regex.compile!("[^0-9a-zA-Z!.*/'()_-]")
   def strict_encode(name) do
     String.replace(name, @regex, "-")
index c0b22c28a4cf7af16b37767f12b7fb2ff9808a6b..d71e213d28e7f1766507c86ad8b6758ab409a971 100644 (file)
@@ -36,6 +36,8 @@ defmodule Pleroma.Uploaders.Uploader do
   @callback put_file(Pleroma.Upload.t()) ::
               :ok | {:ok, file_spec()} | {:error, String.t()} | :wait_callback
 
+  @callback delete_file(file :: String.t()) :: :ok | {:error, String.t()}
+
   @callback http_callback(Plug.Conn.t(), Map.t()) ::
               {:ok, Plug.Conn.t()}
               | {:ok, Plug.Conn.t(), file_spec()}
@@ -43,7 +45,6 @@ defmodule Pleroma.Uploaders.Uploader do
   @optional_callbacks http_callback: 2
 
   @spec put_file(module(), Pleroma.Upload.t()) :: {:ok, file_spec()} | {:error, String.t()}
-
   def put_file(uploader, upload) do
     case uploader.put_file(upload) do
       :ok -> {:ok, {:file, upload.path}}
index db072bad2fd4d9256b29453a4ab9009b8c4a0f40..e4e3ab44a978ed250f2803f93e70ea6de68b6d61 100644 (file)
@@ -264,6 +264,10 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
         "rel" => "self",
         "type" => "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"",
         "href" => user.ap_id
+      },
+      %{
+        "rel" => "http://ostatus.org/schema/1.0/subscribe",
+        "template" => "#{Pleroma.Web.base_url()}/ostatus_subscribe?acct={uri}"
       }
     ]
   end
index 382ecf426cdcea8c7675422827bca4051be2dd00..589d11901a0ceb91f50d5da672a909805c0c25ac 100644 (file)
@@ -15,6 +15,7 @@ defmodule Pleroma.Web.Metadata.Utils do
     |> String.replace(~r/<br\s?\/?>/, " ")
     |> HTML.get_cached_stripped_html_for_activity(object, "metadata")
     |> Emoji.Formatter.demojify()
+    |> HtmlEntities.decode()
     |> Formatter.truncate()
   end
 
@@ -25,6 +26,7 @@ defmodule Pleroma.Web.Metadata.Utils do
     |> String.replace(~r/<br\s?\/?>/, " ")
     |> HTML.strip_tags()
     |> Emoji.Formatter.demojify()
+    |> HtmlEntities.decode()
     |> Formatter.truncate(max_length)
   end
 
index f6c1282832b23de5d5d565a931d950ffbdebd342..9654ab8a3fe7402c358edc8654bffb9a7c6c487b 100644 (file)
@@ -229,9 +229,9 @@ defmodule Pleroma.Web.Router do
     pipe_through(:pleroma_html)
 
     post("/main/ostatus", UtilController, :remote_subscribe)
-    get("/ostatus_subscribe", UtilController, :remote_follow)
+    get("/ostatus_subscribe", RemoteFollowController, :follow)
 
-    post("/ostatus_subscribe", UtilController, :do_remote_follow)
+    post("/ostatus_subscribe", RemoteFollowController, :do_follow)
   end
 
   scope "/api/pleroma", Pleroma.Web.TwitterAPI do
diff --git a/lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex b/lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex
new file mode 100644 (file)
index 0000000..5ba192c
--- /dev/null
@@ -0,0 +1,11 @@
+<%= if @error == :error do %>
+    <h2>Error fetching user</h2>
+<% else %>
+    <h2>Remote follow</h2>
+    <img height="128" width="128" src="<%= avatar_url(@followee) %>">
+    <p><%= @followee.nickname %></p>
+    <%= form_for @conn, remote_follow_path(@conn, :do_follow), [as: "user"], fn f -> %>
+    <%= hidden_input f, :id, value: @followee.id %>
+    <%= submit "Authorize" %>
+    <% end %>
+<% end %>
diff --git a/lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex b/lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex
new file mode 100644 (file)
index 0000000..df44988
--- /dev/null
@@ -0,0 +1,14 @@
+<%= if @error do %>
+<h2><%= @error %></h2>
+<% end %>
+<h2>Log in to follow</h2>
+<p><%= @followee.nickname %></p>
+<img height="128" width="128" src="<%= avatar_url(@followee) %>">
+<%= form_for @conn, remote_follow_path(@conn, :do_follow), [as: "authorization"], fn f -> %>
+<%= text_input f, :name, placeholder: "Username", required: true %>
+<br>
+<%= password_input f, :password, placeholder: "Password", required: true %>
+<br>
+<%= hidden_input f, :id, value: @followee.id %>
+<%= submit "Authorize" %>
+<% end %>
diff --git a/lib/pleroma/web/templates/twitter_api/util/follow.html.eex b/lib/pleroma/web/templates/twitter_api/util/follow.html.eex
deleted file mode 100644 (file)
index 06359fa..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-<%= if @error == :error do %>
-    <h2>Error fetching user</h2>
-<% else %>
-    <h2>Remote follow</h2>
-    <img width="128" height="128" src="<%= @avatar %>">
-    <p><%= @name %></p>
-    <%= form_for @conn, util_path(@conn, :do_remote_follow), [as: "user"], fn f -> %>
-    <%= hidden_input f, :id, value: @id %>
-    <%= submit "Authorize" %>
-    <% end %>
-<% end %>
diff --git a/lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex b/lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex
deleted file mode 100644 (file)
index 4e3a2be..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-<%= if @error do %>
-    <h2><%= @error %></h2>
-<% end %>
-<h2>Log in to follow</h2>
-<p><%= @name %></p>
-<img height="128" width="128" src="<%= @avatar %>">
-<%= form_for @conn, util_path(@conn, :do_remote_follow), [as: "authorization"], fn f -> %>
-<%= text_input f, :name, placeholder: "Username" %>
-<br>
-<%= password_input f, :password, placeholder: "Password" %>
-<br>
-<%= hidden_input f, :id, value: @id %>
-<%= submit "Authorize" %>
-<% end %>
diff --git a/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex
new file mode 100644 (file)
index 0000000..e0d4d56
--- /dev/null
@@ -0,0 +1,112 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do
+  use Pleroma.Web, :controller
+
+  require Logger
+
+  alias Pleroma.Activity
+  alias Pleroma.Object.Fetcher
+  alias Pleroma.Plugs.OAuthScopesPlug
+  alias Pleroma.User
+  alias Pleroma.Web.Auth.Authenticator
+  alias Pleroma.Web.CommonAPI
+
+  @status_types ["Article", "Event", "Note", "Video", "Page", "Question"]
+
+  # Note: follower can submit the form (with password auth) not being signed in (having no token)
+  plug(
+    OAuthScopesPlug,
+    %{fallback: :proceed_unauthenticated, scopes: ["follow", "write:follows"]}
+    when action in [:do_follow]
+  )
+
+  # GET /ostatus_subscribe
+  #
+  def follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do
+    case is_status?(acct) do
+      true -> follow_status(conn, user, acct)
+      _ -> follow_account(conn, user, acct)
+    end
+  end
+
+  defp follow_status(conn, _user, acct) do
+    with {:ok, object} <- Fetcher.fetch_object_from_id(acct),
+         %Activity{id: activity_id} <- Activity.get_create_by_object_ap_id(object.data["id"]) do
+      redirect(conn, to: o_status_path(conn, :notice, activity_id))
+    else
+      error ->
+        handle_follow_error(conn, error)
+    end
+  end
+
+  defp follow_account(conn, user, acct) do
+    with {:ok, followee} <- User.get_or_fetch(acct) do
+      render(conn, follow_template(user), %{error: false, followee: followee, acct: acct})
+    else
+      {:error, _reason} ->
+        render(conn, follow_template(user), %{error: :error})
+    end
+  end
+
+  defp follow_template(%User{} = _user), do: "follow.html"
+  defp follow_template(_), do: "follow_login.html"
+
+  defp is_status?(acct) do
+    case Fetcher.fetch_and_contain_remote_object_from_id(acct) do
+      {:ok, %{"type" => type}} when type in @status_types ->
+        true
+
+      _ ->
+        false
+    end
+  end
+
+  # POST  /ostatus_subscribe
+  #
+  def do_follow(%{assigns: %{user: %User{} = user}} = conn, %{"user" => %{"id" => id}}) do
+    with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
+         {:ok, _, _, _} <- CommonAPI.follow(user, followee) do
+      render(conn, "followed.html", %{error: false})
+    else
+      error ->
+        handle_follow_error(conn, error)
+    end
+  end
+
+  def do_follow(conn, %{"authorization" => %{"name" => _, "password" => _, "id" => id}}) do
+    with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
+         {_, {:ok, user}, _} <- {:auth, Authenticator.get_user(conn), followee},
+         {:ok, _, _, _} <- CommonAPI.follow(user, followee) do
+      render(conn, "followed.html", %{error: false})
+    else
+      error ->
+        handle_follow_error(conn, error)
+    end
+  end
+
+  def do_follow(%{assigns: %{user: nil}} = conn, _) do
+    Logger.debug("Insufficient permissions: follow | write:follows.")
+    render(conn, "followed.html", %{error: "Insufficient permissions: follow | write:follows."})
+  end
+
+  defp handle_follow_error(conn, {:auth, _, followee} = _) do
+    render(conn, "follow_login.html", %{error: "Wrong username or password", followee: followee})
+  end
+
+  defp handle_follow_error(conn, {:fetch_user, error} = _) do
+    Logger.debug("Remote follow failed with error #{inspect(error)}")
+    render(conn, "followed.html", %{error: "Could not find user"})
+  end
+
+  defp handle_follow_error(conn, {:error, "Could not follow user:" <> _} = _) do
+    render(conn, "followed.html", %{error: "Error following account"})
+  end
+
+  defp handle_follow_error(conn, error) do
+    Logger.debug("Remote follow failed with error #{inspect(error)}")
+    render(conn, "followed.html", %{error: "Something went wrong."})
+  end
+end
index c35e393c072e391b7d7cb4c9deb94d6b76f2e367..f08b9d28c53d057ed088ddd521c34aab37d2e4d5 100644 (file)
@@ -7,12 +7,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
 
   require Logger
 
-  alias Pleroma.Activity
   alias Pleroma.Config
   alias Pleroma.Emoji
   alias Pleroma.Healthcheck
   alias Pleroma.Notification
-  alias Pleroma.Plugs.AuthenticationPlug
   alias Pleroma.Plugs.OAuthScopesPlug
   alias Pleroma.User
   alias Pleroma.Web
@@ -84,105 +82,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
     end
   end
 
-  def remote_follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do
-    if is_status?(acct) do
-      {:ok, object} = Pleroma.Object.Fetcher.fetch_object_from_id(acct)
-      %Activity{id: activity_id} = Activity.get_create_by_object_ap_id(object.data["id"])
-      redirect(conn, to: "/notice/#{activity_id}")
-    else
-      with {:ok, followee} <- User.get_or_fetch(acct) do
-        conn
-        |> render(follow_template(user), %{
-          error: false,
-          acct: acct,
-          avatar: User.avatar_url(followee),
-          name: followee.nickname,
-          id: followee.id
-        })
-      else
-        {:error, _reason} ->
-          render(conn, follow_template(user), %{error: :error})
-      end
-    end
-  end
-
-  defp follow_template(%User{} = _user), do: "follow.html"
-  defp follow_template(_), do: "follow_login.html"
-
-  defp is_status?(acct) do
-    case Pleroma.Object.Fetcher.fetch_and_contain_remote_object_from_id(acct) do
-      {:ok, %{"type" => type}}
-      when type in ["Article", "Event", "Note", "Video", "Page", "Question"] ->
-        true
-
-      _ ->
-        false
-    end
-  end
-
-  def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}})
-      when not is_nil(user) do
-    with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
-         {:ok, _follower, _followee, _activity} <- CommonAPI.follow(user, followee) do
-      conn
-      |> render("followed.html", %{error: false})
-    else
-      # Was already following user
-      {:error, "Could not follow user:" <> _rest} ->
-        render(conn, "followed.html", %{error: "Error following account"})
-
-      {:fetch_user, error} ->
-        Logger.debug("Remote follow failed with error #{inspect(error)}")
-        render(conn, "followed.html", %{error: "Could not find user"})
-
-      e ->
-        Logger.debug("Remote follow failed with error #{inspect(e)}")
-        render(conn, "followed.html", %{error: "Something went wrong."})
-    end
-  end
-
-  # Note: "id" is the id of followee user, disregard incorrect placing under "authorization"
-  def do_remote_follow(conn, %{
-        "authorization" => %{"name" => username, "password" => password, "id" => id}
-      }) do
-    with %User{} = followee <- User.get_cached_by_id(id),
-         {_, %User{} = user, _} <- {:auth, User.get_cached_by_nickname(username), followee},
-         {_, true, _} <- {
-           :auth,
-           AuthenticationPlug.checkpw(password, user.password_hash),
-           followee
-         },
-         {:ok, _follower, _followee, _activity} <- CommonAPI.follow(user, followee) do
-      conn
-      |> render("followed.html", %{error: false})
-    else
-      # Was already following user
-      {:error, "Could not follow user:" <> _rest} ->
-        render(conn, "followed.html", %{error: "Error following account"})
-
-      {:auth, _, followee} ->
-        conn
-        |> render("follow_login.html", %{
-          error: "Wrong username or password",
-          id: id,
-          name: followee.nickname,
-          avatar: User.avatar_url(followee)
-        })
-
-      e ->
-        Logger.debug("Remote follow failed with error #{inspect(e)}")
-        render(conn, "followed.html", %{error: "Something went wrong."})
-    end
-  end
-
-  def do_remote_follow(%{assigns: %{user: nil}} = conn, _) do
-    render(conn, "followed.html", %{error: "Insufficient permissions: follow | write:follows."})
-  end
-
-  def do_remote_follow(conn, _) do
-    render(conn, "followed.html", %{error: "Something went wrong."})
-  end
-
   def notifications_read(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do
     with {:ok, _} <- Notification.read_one(user, notification_id) do
       json(conn, %{status: "success"})
diff --git a/lib/pleroma/web/twitter_api/views/remote_follow_view.ex b/lib/pleroma/web/twitter_api/views/remote_follow_view.ex
new file mode 100644 (file)
index 0000000..d469c47
--- /dev/null
@@ -0,0 +1,10 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.TwitterAPI.RemoteFollowView do
+  use Pleroma.Web, :view
+  import Phoenix.HTML.Form
+
+  defdelegate avatar_url(user), to: Pleroma.User
+end
index ba81c0d4bb2eb42025fcb07eb6996ffebfa94954..ab9f27b2f1b48ce846cd71e3586e47d3c9706f3b 100644 (file)
@@ -125,9 +125,10 @@ defmodule Pleroma.Conversation.ParticipationTest do
 
   test "it marks a participation as read" do
     participation = insert(:participation, %{read: false})
-    {:ok, participation} = Participation.mark_as_read(participation)
+    {:ok, updated_participation} = Participation.mark_as_read(participation)
 
-    assert participation.read
+    assert updated_participation.read
+    assert updated_participation.updated_at == participation.updated_at
   end
 
   test "it marks a participation as unread" do
index 9247a6d841a06276b23e2bf3104aafd5502ed2f6..b002c2bae96ebf2fb0b5cd4f1778c73f83d824ce 100644 (file)
@@ -71,6 +71,74 @@ defmodule Pleroma.ObjectTest do
     end
   end
 
+  describe "delete attachments" do
+    clear_config([Pleroma.Upload])
+
+    test "in subdirectories" do
+      Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
+
+      file = %Plug.Upload{
+        content_type: "image/jpg",
+        path: Path.absname("test/fixtures/image.jpg"),
+        filename: "an_image.jpg"
+      }
+
+      user = insert(:user)
+
+      {:ok, %Object{} = attachment} =
+        Pleroma.Web.ActivityPub.ActivityPub.upload(file, actor: user.ap_id)
+
+      %{data: %{"attachment" => [%{"url" => [%{"href" => href}]}]}} =
+        note = insert(:note, %{user: user, data: %{"attachment" => [attachment.data]}})
+
+      uploads_dir = Pleroma.Config.get!([Pleroma.Uploaders.Local, :uploads])
+
+      path = href |> Path.dirname() |> Path.basename()
+
+      assert {:ok, ["an_image.jpg"]} == File.ls("#{uploads_dir}/#{path}")
+
+      Object.delete(note)
+
+      assert Object.get_by_id(attachment.id) == nil
+
+      assert {:ok, []} == File.ls("#{uploads_dir}/#{path}")
+    end
+
+    test "with dedupe enabled" do
+      Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
+      Pleroma.Config.put([Pleroma.Upload, :filters], [Pleroma.Upload.Filter.Dedupe])
+
+      uploads_dir = Pleroma.Config.get!([Pleroma.Uploaders.Local, :uploads])
+
+      File.mkdir_p!(uploads_dir)
+
+      file = %Plug.Upload{
+        content_type: "image/jpg",
+        path: Path.absname("test/fixtures/image.jpg"),
+        filename: "an_image.jpg"
+      }
+
+      user = insert(:user)
+
+      {:ok, %Object{} = attachment} =
+        Pleroma.Web.ActivityPub.ActivityPub.upload(file, actor: user.ap_id)
+
+      %{data: %{"attachment" => [%{"url" => [%{"href" => href}]}]}} =
+        note = insert(:note, %{user: user, data: %{"attachment" => [attachment.data]}})
+
+      filename = Path.basename(href)
+
+      assert {:ok, files} = File.ls(uploads_dir)
+      assert filename in files
+
+      Object.delete(note)
+
+      assert Object.get_by_id(attachment.id) == nil
+      assert {:ok, files} = File.ls(uploads_dir)
+      refute filename in files
+    end
+  end
+
   describe "normalizer" do
     test "fetches unknown objects by default" do
       %Object{} =
index fc442d0f1fe58b53b16ba1ea92f17066ff1b84f1..1963dac232137ff8445a433ffdf340a5e5ecd1eb 100644 (file)
@@ -29,4 +29,25 @@ defmodule Pleroma.Uploaders.LocalTest do
              |> File.exists?()
     end
   end
+
+  describe "delete_file/1" do
+    test "deletes local file" do
+      file_path = "local_upload/files/image.jpg"
+
+      file = %Pleroma.Upload{
+        name: "image.jpg",
+        content_type: "image/jpg",
+        path: file_path,
+        tempfile: Path.absname("test/fixtures/image_tmp.jpg")
+      }
+
+      :ok = Local.put_file(file)
+      local_path = Path.join([Local.upload_path(), file_path])
+      assert File.exists?(local_path)
+
+      Local.delete_file(file_path)
+
+      refute File.exists?(local_path)
+    end
+  end
 end
diff --git a/test/uploaders/mdii_test.exs b/test/uploaders/mdii_test.exs
deleted file mode 100644 (file)
index d432d40..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Uploaders.MDIITest do
-  use Pleroma.DataCase
-  alias Pleroma.Uploaders.MDII
-  import Tesla.Mock
-
-  describe "get_file/1" do
-    test "it returns path to local folder for files" do
-      assert MDII.get_file("") == {:ok, {:static_dir, "test/uploads"}}
-    end
-  end
-
-  describe "put_file/1" do
-    setup do
-      file_upload = %Pleroma.Upload{
-        name: "mdii-image.jpg",
-        content_type: "image/jpg",
-        path: "test_folder/mdii-image.jpg",
-        tempfile: Path.absname("test/fixtures/image_tmp.jpg")
-      }
-
-      [file_upload: file_upload]
-    end
-
-    test "save file", %{file_upload: file_upload} do
-      mock(fn
-        %{method: :post, url: "https://mdii.sakura.ne.jp/mdii-post.cgi?jpg"} ->
-          %Tesla.Env{status: 200, body: "mdii-image"}
-      end)
-
-      assert MDII.put_file(file_upload) ==
-               {:ok, {:url, "https://mdii.sakura.ne.jp/mdii-image.jpg"}}
-    end
-
-    test "save file to local if MDII  isn`t available", %{file_upload: file_upload} do
-      mock(fn
-        %{method: :post, url: "https://mdii.sakura.ne.jp/mdii-post.cgi?jpg"} ->
-          %Tesla.Env{status: 500}
-      end)
-
-      assert MDII.put_file(file_upload) == :ok
-
-      assert Path.join([Pleroma.Uploaders.Local.upload_path(), file_upload.path])
-             |> File.exists?()
-    end
-  end
-end
index 171316340db8ead0811158546a8be01981447215..ab7795c3bea51251c01a0067b0f4ca2787420073 100644 (file)
@@ -79,4 +79,11 @@ defmodule Pleroma.Uploaders.S3Test do
       end
     end
   end
+
+  describe "delete_file/1" do
+    test_with_mock "deletes file", ExAws, request: fn _req -> {:ok, %{status_code: 204}} end do
+      assert :ok = S3.delete_file("image.jpg")
+      assert_called(ExAws.request(:_))
+    end
+  end
 end
index e885e5a5abb87bde31302f93562e97e6555d4cb7..015af19abe5b3691d9f908f481f01a73d4daa7d6 100644 (file)
@@ -23,6 +23,27 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
     :ok
   end
 
+  describe "gather_webfinger_links/1" do
+    test "it returns links" do
+      user = insert(:user)
+
+      expected_links = [
+        %{"href" => user.ap_id, "rel" => "self", "type" => "application/activity+json"},
+        %{
+          "href" => user.ap_id,
+          "rel" => "self",
+          "type" => "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
+        },
+        %{
+          "rel" => "http://ostatus.org/schema/1.0/subscribe",
+          "template" => "#{Pleroma.Web.base_url()}/ostatus_subscribe?acct={uri}"
+        }
+      ]
+
+      assert expected_links == Publisher.gather_webfinger_links(user)
+    end
+  end
+
   describe "determine_inbox/2" do
     test "it returns sharedInbox for messages involving as:Public in to" do
       user =
diff --git a/test/web/metadata/utils_test.exs b/test/web/metadata/utils_test.exs
new file mode 100644 (file)
index 0000000..7547f29
--- /dev/null
@@ -0,0 +1,32 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Metadata.UtilsTest do
+  use Pleroma.DataCase
+  import Pleroma.Factory
+  alias Pleroma.Web.Metadata.Utils
+
+  describe "scrub_html_and_truncate/1" do
+    test "it returns text without encode HTML" do
+      user = insert(:user)
+
+      note =
+        insert(:note, %{
+          data: %{
+            "actor" => user.ap_id,
+            "id" => "https://pleroma.gov/objects/whatever",
+            "content" => "Pleroma's really cool!"
+          }
+        })
+
+      assert Utils.scrub_html_and_truncate(note) == "Pleroma's really cool!"
+    end
+  end
+
+  describe "scrub_html_and_truncate/2" do
+    test "it returns text without encode HTML" do
+      assert Utils.scrub_html_and_truncate("Pleroma's really cool!") == "Pleroma's really cool!"
+    end
+  end
+end
diff --git a/test/web/twitter_api/remote_follow_controller_test.exs b/test/web/twitter_api/remote_follow_controller_test.exs
new file mode 100644 (file)
index 0000000..4449493
--- /dev/null
@@ -0,0 +1,235 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
+  use Pleroma.Web.ConnCase
+
+  alias Pleroma.User
+  alias Pleroma.Web.CommonAPI
+  import ExUnit.CaptureLog
+  import Pleroma.Factory
+
+  setup do
+    Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+    :ok
+  end
+
+  clear_config([:instance])
+  clear_config([:frontend_configurations, :pleroma_fe])
+  clear_config([:user, :deny_follow_blocked])
+
+  describe "GET /ostatus_subscribe - remote_follow/2" do
+    test "adds status to pleroma instance if the `acct` is a status", %{conn: conn} do
+      assert conn
+             |> get(
+               remote_follow_path(conn, :follow, %{
+                 acct: "https://mastodon.social/users/emelie/statuses/101849165031453009"
+               })
+             )
+             |> redirected_to() =~ "/notice/"
+    end
+
+    test "show follow account page if the `acct` is a account link", %{conn: conn} do
+      response =
+        conn
+        |> get(remote_follow_path(conn, :follow, %{acct: "https://mastodon.social/users/emelie"}))
+        |> html_response(200)
+
+      assert response =~ "Log in to follow"
+    end
+
+    test "show follow page if the `acct` is a account link", %{conn: conn} do
+      user = insert(:user)
+
+      response =
+        conn
+        |> assign(:user, user)
+        |> get(remote_follow_path(conn, :follow, %{acct: "https://mastodon.social/users/emelie"}))
+        |> html_response(200)
+
+      assert response =~ "Remote follow"
+    end
+
+    test "show follow page with error when user cannot fecth by `acct` link", %{conn: conn} do
+      user = insert(:user)
+
+      assert capture_log(fn ->
+               response =
+                 conn
+                 |> assign(:user, user)
+                 |> get(
+                   remote_follow_path(conn, :follow, %{
+                     acct: "https://mastodon.social/users/not_found"
+                   })
+                 )
+                 |> html_response(200)
+
+               assert response =~ "Error fetching user"
+             end) =~ "Object has been deleted"
+    end
+  end
+
+  describe "POST /ostatus_subscribe - do_follow/2 with assigned user " do
+    test "required `follow | write:follows` scope", %{conn: conn} do
+      user = insert(:user)
+      user2 = insert(:user)
+      read_token = insert(:oauth_token, user: user, scopes: ["read"])
+
+      assert capture_log(fn ->
+               response =
+                 conn
+                 |> assign(:user, user)
+                 |> assign(:token, read_token)
+                 |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}})
+                 |> response(200)
+
+               assert response =~ "Error following account"
+             end) =~ "Insufficient permissions: follow | write:follows."
+    end
+
+    test "follows user", %{conn: conn} do
+      user = insert(:user)
+      user2 = insert(:user)
+
+      response =
+        conn
+        |> assign(:user, user)
+        |> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"]))
+        |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}})
+        |> response(200)
+
+      assert response =~ "Account followed!"
+      assert user2.follower_address in User.following(user)
+    end
+
+    test "returns error when user is deactivated", %{conn: conn} do
+      user = insert(:user, deactivated: true)
+      user2 = insert(:user)
+
+      response =
+        conn
+        |> assign(:user, user)
+        |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}})
+        |> response(200)
+
+      assert response =~ "Error following account"
+    end
+
+    test "returns error when user is blocked", %{conn: conn} do
+      Pleroma.Config.put([:user, :deny_follow_blocked], true)
+      user = insert(:user)
+      user2 = insert(:user)
+
+      {:ok, _user_block} = Pleroma.User.block(user2, user)
+
+      response =
+        conn
+        |> assign(:user, user)
+        |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}})
+        |> response(200)
+
+      assert response =~ "Error following account"
+    end
+
+    test "returns error when followee not found", %{conn: conn} do
+      user = insert(:user)
+
+      response =
+        conn
+        |> assign(:user, user)
+        |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => "jimm"}})
+        |> response(200)
+
+      assert response =~ "Error following account"
+    end
+
+    test "returns success result when user already in followers", %{conn: conn} do
+      user = insert(:user)
+      user2 = insert(:user)
+      {:ok, _, _, _} = CommonAPI.follow(user, user2)
+
+      response =
+        conn
+        |> assign(:user, refresh_record(user))
+        |> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"]))
+        |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}})
+        |> response(200)
+
+      assert response =~ "Account followed!"
+    end
+  end
+
+  describe "POST /ostatus_subscribe - follow/2 without assigned user " do
+    test "follows", %{conn: conn} do
+      user = insert(:user)
+      user2 = insert(:user)
+
+      response =
+        conn
+        |> post(remote_follow_path(conn, :do_follow), %{
+          "authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id}
+        })
+        |> response(200)
+
+      assert response =~ "Account followed!"
+      assert user2.follower_address in User.following(user)
+    end
+
+    test "returns error when followee not found", %{conn: conn} do
+      user = insert(:user)
+
+      response =
+        conn
+        |> post(remote_follow_path(conn, :do_follow), %{
+          "authorization" => %{"name" => user.nickname, "password" => "test", "id" => "jimm"}
+        })
+        |> response(200)
+
+      assert response =~ "Error following account"
+    end
+
+    test "returns error when login invalid", %{conn: conn} do
+      user = insert(:user)
+
+      response =
+        conn
+        |> post(remote_follow_path(conn, :do_follow), %{
+          "authorization" => %{"name" => "jimm", "password" => "test", "id" => user.id}
+        })
+        |> response(200)
+
+      assert response =~ "Wrong username or password"
+    end
+
+    test "returns error when password invalid", %{conn: conn} do
+      user = insert(:user)
+      user2 = insert(:user)
+
+      response =
+        conn
+        |> post(remote_follow_path(conn, :do_follow), %{
+          "authorization" => %{"name" => user.nickname, "password" => "42", "id" => user2.id}
+        })
+        |> response(200)
+
+      assert response =~ "Wrong username or password"
+    end
+
+    test "returns error when user is blocked", %{conn: conn} do
+      Pleroma.Config.put([:user, :deny_follow_blocked], true)
+      user = insert(:user)
+      user2 = insert(:user)
+      {:ok, _user_block} = Pleroma.User.block(user2, user)
+
+      response =
+        conn
+        |> post(remote_follow_path(conn, :do_follow), %{
+          "authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id}
+        })
+        |> response(200)
+
+      assert response =~ "Error following account"
+    end
+  end
+end
index 9bfaba9d333bdc569a5a1ebdbba0218bec5c21a8..8418fd071f26e7eece7ea04d7d48afaeff77427e 100644 (file)
@@ -319,204 +319,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
     end
   end
 
-  describe "GET /ostatus_subscribe - remote_follow/2" do
-    test "adds status to pleroma instance if the `acct` is a status", %{conn: conn} do
-      conn =
-        get(
-          conn,
-          "/ostatus_subscribe?acct=https://mastodon.social/users/emelie/statuses/101849165031453009"
-        )
-
-      assert redirected_to(conn) =~ "/notice/"
-    end
-
-    test "show follow account page if the `acct` is a account link", %{conn: conn} do
-      response =
-        get(
-          conn,
-          "/ostatus_subscribe?acct=https://mastodon.social/users/emelie"
-        )
-
-      assert html_response(response, 200) =~ "Log in to follow"
-    end
-
-    test "show follow page if the `acct` is a account link", %{conn: conn} do
-      user = insert(:user)
-
-      response =
-        conn
-        |> assign(:user, user)
-        |> get("/ostatus_subscribe?acct=https://mastodon.social/users/emelie")
-
-      assert html_response(response, 200) =~ "Remote follow"
-    end
-
-    test "show follow page with error when user cannot fecth by `acct` link", %{conn: conn} do
-      user = insert(:user)
-
-      assert capture_log(fn ->
-               response =
-                 conn
-                 |> assign(:user, user)
-                 |> get("/ostatus_subscribe?acct=https://mastodon.social/users/not_found")
-
-               assert html_response(response, 200) =~ "Error fetching user"
-             end) =~ "Object has been deleted"
-    end
-  end
-
-  describe "POST /ostatus_subscribe - do_remote_follow/2 with assigned user" do
-    setup do: oauth_access(["follow"])
-
-    test "follows user", %{user: user, conn: conn} do
-      user2 = insert(:user)
-
-      response =
-        conn
-        |> post("/ostatus_subscribe", %{"user" => %{"id" => user2.id}})
-        |> response(200)
-
-      assert response =~ "Account followed!"
-      assert user2.follower_address in User.following(user)
-    end
-
-    test "returns error when user is deactivated" do
-      user = insert(:user, deactivated: true)
-      user2 = insert(:user)
-
-      response =
-        build_conn()
-        |> assign(:user, user)
-        |> assign(:token, insert(:oauth_token, user: user, scopes: ["follow"]))
-        |> post("/ostatus_subscribe", %{"user" => %{"id" => user2.id}})
-        |> response(200)
-
-      assert response =~ "Error following account"
-    end
-
-    test "returns error when user is blocked", %{user: user, conn: conn} do
-      Pleroma.Config.put([:user, :deny_follow_blocked], true)
-      user2 = insert(:user)
-
-      {:ok, _user_block} = Pleroma.User.block(user2, user)
-
-      response =
-        conn
-        |> post("/ostatus_subscribe", %{"user" => %{"id" => user2.id}})
-        |> response(200)
-
-      assert response =~ "Error following account"
-    end
-
-    test "returns error on insufficient permissions", %{user: user, conn: conn} do
-      user2 = insert(:user)
-
-      for token <- [nil, insert(:oauth_token, user: user, scopes: ["read"])] do
-        response =
-          conn
-          |> assign(:token, token)
-          |> post("/ostatus_subscribe", %{"user" => %{"id" => user2.id}})
-          |> response(200)
-
-        assert response =~ "Error following account"
-      end
-    end
-
-    test "returns error when followee not found", %{conn: conn} do
-      response =
-        conn
-        |> post("/ostatus_subscribe", %{"user" => %{"id" => "jimm"}})
-        |> response(200)
-
-      assert response =~ "Error following account"
-    end
-
-    test "returns success result when user already in followers", %{user: user, conn: conn} do
-      user2 = insert(:user)
-      {:ok, _, _, _} = CommonAPI.follow(user, user2)
-
-      response =
-        conn
-        |> post("/ostatus_subscribe", %{"user" => %{"id" => user2.id}})
-        |> response(200)
-
-      assert response =~ "Account followed!"
-    end
-  end
-
-  describe "POST /ostatus_subscribe - do_remote_follow/2 without assigned user" do
-    test "follows", %{conn: conn} do
-      user = insert(:user)
-      user2 = insert(:user)
-
-      response =
-        conn
-        |> post("/ostatus_subscribe", %{
-          "authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id}
-        })
-        |> response(200)
-
-      assert response =~ "Account followed!"
-      assert user2.follower_address in User.following(user)
-    end
-
-    test "returns error when followee not found", %{conn: conn} do
-      user = insert(:user)
-
-      response =
-        conn
-        |> post("/ostatus_subscribe", %{
-          "authorization" => %{"name" => user.nickname, "password" => "test", "id" => "jimm"}
-        })
-        |> response(200)
-
-      assert response =~ "Error following account"
-    end
-
-    test "returns error when login invalid", %{conn: conn} do
-      user = insert(:user)
-
-      response =
-        conn
-        |> post("/ostatus_subscribe", %{
-          "authorization" => %{"name" => "jimm", "password" => "test", "id" => user.id}
-        })
-        |> response(200)
-
-      assert response =~ "Wrong username or password"
-    end
-
-    test "returns error when password invalid", %{conn: conn} do
-      user = insert(:user)
-      user2 = insert(:user)
-
-      response =
-        conn
-        |> post("/ostatus_subscribe", %{
-          "authorization" => %{"name" => user.nickname, "password" => "42", "id" => user2.id}
-        })
-        |> response(200)
-
-      assert response =~ "Wrong username or password"
-    end
-
-    test "returns error when user is blocked", %{conn: conn} do
-      Pleroma.Config.put([:user, :deny_follow_blocked], true)
-      user = insert(:user)
-      user2 = insert(:user)
-      {:ok, _user_block} = Pleroma.User.block(user2, user)
-
-      response =
-        conn
-        |> post("/ostatus_subscribe", %{
-          "authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id}
-        })
-        |> response(200)
-
-      assert response =~ "Error following account"
-    end
-  end
-
   describe "GET /api/pleroma/healthcheck" do
     clear_config([:instance, :healthcheck])