From 29b7e822fbd5a9001cd31705da5f46672941813c Mon Sep 17 00:00:00 2001
From: Sebastian Huebner <sebastian@hueb-ner.de>
Date: Tue, 9 Jan 2018 12:31:11 +0100
Subject: [PATCH 01/16] added question about activating mediaproxy to config
 generator

---
 lib/mix/tasks/generate_config.ex | 3 ++-
 lib/mix/tasks/sample_config.eex  | 5 +++++
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/lib/mix/tasks/generate_config.ex b/lib/mix/tasks/generate_config.ex
index f20f93e4d..0dfbda226 100644
--- a/lib/mix/tasks/generate_config.ex
+++ b/lib/mix/tasks/generate_config.ex
@@ -8,11 +8,12 @@ defmodule Mix.Tasks.GenerateConfig do
     domain = IO.gets("What is your domain name? (e.g. pleroma.soykaf.com): ") |> String.trim
     name = IO.gets("What is the name of your instance? (e.g. Pleroma/Soykaf): ") |> String.trim
     email = IO.gets("What's your admin email address: ") |> String.trim
+    mediaproxy = IO.gets("Do you want to activate the mediaproxy? (true/false): ") |> String.trim
     secret =  :crypto.strong_rand_bytes(64) |> Base.encode64 |> binary_part(0, 64)
     dbpass =  :crypto.strong_rand_bytes(64) |> Base.encode64 |> binary_part(0, 64)
 
     resultSql = EEx.eval_file("lib/mix/tasks/sample_psql.eex", [dbpass: dbpass])
-    result = EEx.eval_file("lib/mix/tasks/sample_config.eex", [domain: domain, email: email, name: name, secret: secret, dbpass: dbpass])
+    result = EEx.eval_file("lib/mix/tasks/sample_config.eex", [domain: domain, email: email, name: name, secret: secret, mediaproxy: mediaproxy, dbpass: dbpass])
 
     IO.puts("\nWriting config to config/generated_config.exs.\n\nCheck it and configure your database, then copy it to either config/dev.secret.exs or config/prod.secret.exs")
     File.write("config/generated_config.exs", result)
diff --git a/lib/mix/tasks/sample_config.eex b/lib/mix/tasks/sample_config.eex
index 85a7c554e..05f11c95d 100644
--- a/lib/mix/tasks/sample_config.eex
+++ b/lib/mix/tasks/sample_config.eex
@@ -10,6 +10,11 @@ config :pleroma, :instance,
   limit: 5000,
   registrations_open: true
 
+config :pleroma, :media_proxy,
+  enabled: <%= mediaproxy %>,
+  redirect_on_failure: true,
+  #base_url: "https://cache.pleroma.social"
+
 # Configure your database
 config :pleroma, Pleroma.Repo,
   adapter: Ecto.Adapters.Postgres,

From d56ab43609985801c853b8743f4c33f691f59924 Mon Sep 17 00:00:00 2001
From: eal <eal@waifu.club>
Date: Fri, 12 Jan 2018 22:38:14 +0200
Subject: [PATCH 02/16] Ask for proxy URL if proxy enabled.

Also change the true/false question to y/n
---
 lib/mix/tasks/generate_config.ex | 12 ++++++++++--
 lib/mix/tasks/sample_config.eex  |  2 +-
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/lib/mix/tasks/generate_config.ex b/lib/mix/tasks/generate_config.ex
index 0dfbda226..2d962124f 100644
--- a/lib/mix/tasks/generate_config.ex
+++ b/lib/mix/tasks/generate_config.ex
@@ -8,12 +8,20 @@ defmodule Mix.Tasks.GenerateConfig do
     domain = IO.gets("What is your domain name? (e.g. pleroma.soykaf.com): ") |> String.trim
     name = IO.gets("What is the name of your instance? (e.g. Pleroma/Soykaf): ") |> String.trim
     email = IO.gets("What's your admin email address: ") |> String.trim
-    mediaproxy = IO.gets("Do you want to activate the mediaproxy? (true/false): ") |> String.trim
+    mediaproxy = IO.gets("Do you want to activate the mediaproxy? (y/N): ")
+    |> String.trim()
+    |> String.downcase()
+    |> String.starts_with?("y")
+    proxy_url = if mediaproxy do
+      IO.gets("What is the mediaproxy's URL? (e.g. https://cache.example.com): ") |> String.trim
+    else
+      "https://cache.example.com"
+    end
     secret =  :crypto.strong_rand_bytes(64) |> Base.encode64 |> binary_part(0, 64)
     dbpass =  :crypto.strong_rand_bytes(64) |> Base.encode64 |> binary_part(0, 64)
 
     resultSql = EEx.eval_file("lib/mix/tasks/sample_psql.eex", [dbpass: dbpass])
-    result = EEx.eval_file("lib/mix/tasks/sample_config.eex", [domain: domain, email: email, name: name, secret: secret, mediaproxy: mediaproxy, dbpass: dbpass])
+    result = EEx.eval_file("lib/mix/tasks/sample_config.eex", [domain: domain, email: email, name: name, secret: secret, mediaproxy: mediaproxy, proxy_url: proxy_url, dbpass: dbpass])
 
     IO.puts("\nWriting config to config/generated_config.exs.\n\nCheck it and configure your database, then copy it to either config/dev.secret.exs or config/prod.secret.exs")
     File.write("config/generated_config.exs", result)
diff --git a/lib/mix/tasks/sample_config.eex b/lib/mix/tasks/sample_config.eex
index 05f11c95d..9330fae2d 100644
--- a/lib/mix/tasks/sample_config.eex
+++ b/lib/mix/tasks/sample_config.eex
@@ -13,7 +13,7 @@ config :pleroma, :instance,
 config :pleroma, :media_proxy,
   enabled: <%= mediaproxy %>,
   redirect_on_failure: true,
-  #base_url: "https://cache.pleroma.social"
+  base_url: "<%= proxy_url %>"
 
 # Configure your database
 config :pleroma, Pleroma.Repo,

From 9717166d105cec6f9c878653aec2d409265e80a6 Mon Sep 17 00:00:00 2001
From: eal <eal@waifu.club>
Date: Sat, 13 Jan 2018 18:24:16 +0200
Subject: [PATCH 03/16] Add a stats agent for storing data from expensive
 queries.

---
 lib/pleroma/application.ex                    |  1 +
 lib/pleroma/stats.ex                          | 38 +++++++++++++++++++
 .../mastodon_api/mastodon_api_controller.ex   | 12 ++++--
 lib/pleroma/web/router.ex                     |  1 +
 4 files changed, 49 insertions(+), 3 deletions(-)
 create mode 100644 lib/pleroma/stats.ex

diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
index 2969ca3c4..cdfca8b1a 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -21,6 +21,7 @@ defmodule Pleroma.Application do
                        ]]),
       worker(Pleroma.Web.Federator, []),
       worker(Pleroma.Web.ChatChannel.ChatChannelState, []),
+      worker(Pleroma.Stats, []),
     ]
     ++ if Mix.env == :test, do: [], else: [worker(Pleroma.Web.Streamer, [])]
 
diff --git a/lib/pleroma/stats.ex b/lib/pleroma/stats.ex
new file mode 100644
index 000000000..45fa27b55
--- /dev/null
+++ b/lib/pleroma/stats.ex
@@ -0,0 +1,38 @@
+defmodule Pleroma.Stats do
+  use Agent
+  import Ecto.Query
+  alias Pleroma.{User, Repo, Activity}
+
+  def start_link do
+    agent = Agent.start_link(fn -> %{} end, name: __MODULE__)
+    schedule_update()
+    agent
+  end
+
+  def get do
+    Agent.get(__MODULE__, fn stats -> stats end)
+  end
+
+  def schedule_update do
+    update_stats()
+    spawn(fn ->
+      Process.sleep(1000 * 60 * 60 * 1) # 1 hour
+      schedule_update()
+    end)
+  end
+
+  def update_stats do
+    peers = from(u in Pleroma.User,
+      select: fragment("?->'host'", u.info),
+      where: u.local != ^true)
+    |> Repo.all() |> Enum.uniq()
+    domain_count = Enum.count(peers)
+    status_query = from p in Activity,
+      where: p.local == ^true,
+      where: fragment("?->'object'->>'type' = ?", p.data, ^"Note")
+    status_count = Repo.aggregate(status_query, :count, :id)
+    Agent.update(__MODULE__, fn _ ->
+      %{peers: peers, domain_count: domain_count, status_count: status_count}
+    end)
+  end
+end
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index ffa6f42c8..6ca7a6076 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -1,6 +1,6 @@
 defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   use Pleroma.Web, :controller
-  alias Pleroma.{Repo, Activity, User, Notification}
+  alias Pleroma.{Repo, Activity, User, Notification, Stats}
   alias Pleroma.Web
   alias Pleroma.Web.MastodonAPI.{StatusView, AccountView, MastodonView}
   alias Pleroma.Web.ActivityPub.ActivityPub
@@ -94,6 +94,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
 
   def masto_instance(conn, _params) do
     user_count = Repo.aggregate(User.local_user_query, :count, :id)
+    %{domain_count: domain_count, status_count: status_count} = Stats.get()
     response = %{
       uri: Web.base_url,
       title: Keyword.get(@instance, :name),
@@ -104,9 +105,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
         streaming_api: String.replace(Web.base_url, ["http","https"], "wss")
       },
       stats: %{
-        status_count: 2,
+        status_count: status_count,
         user_count: user_count,
-        domain_count: 3
+        domain_count: domain_count
       },
       max_toot_chars: Keyword.get(@instance, :limit)
     }
@@ -114,6 +115,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     json(conn, response)
   end
 
+  def peers(conn, _params) do
+    %{peers: peers} = Stats.get()
+    json(conn, peers)
+  end
+
   defp mastodonized_emoji do
     Pleroma.Formatter.get_custom_emoji()
     |> Enum.map(fn {shortcode, relative_url} ->
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 8e6681e68..09104fc86 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -106,6 +106,7 @@ defmodule Pleroma.Web.Router do
   scope "/api/v1", Pleroma.Web.MastodonAPI do
     pipe_through :api
     get "/instance", MastodonAPIController, :masto_instance
+    get "/instance/peers", MastodonAPIController, :peers
     post "/apps", MastodonAPIController, :create_app
     get "/custom_emojis", MastodonAPIController, :custom_emojis
 

From d8db39564eb21d9d9b572baae1886af8d0c047d5 Mon Sep 17 00:00:00 2001
From: eal <eal@waifu.club>
Date: Sun, 14 Jan 2018 08:15:11 +0200
Subject: [PATCH 04/16] Move user count to stats agent.

---
 lib/pleroma/stats.ex                                | 13 +++++++++----
 .../web/mastodon_api/mastodon_api_controller.ex     | 11 ++---------
 2 files changed, 11 insertions(+), 13 deletions(-)

diff --git a/lib/pleroma/stats.ex b/lib/pleroma/stats.ex
index 45fa27b55..938e5c343 100644
--- a/lib/pleroma/stats.ex
+++ b/lib/pleroma/stats.ex
@@ -4,13 +4,17 @@ defmodule Pleroma.Stats do
   alias Pleroma.{User, Repo, Activity}
 
   def start_link do
-    agent = Agent.start_link(fn -> %{} end, name: __MODULE__)
+    agent = Agent.start_link(fn -> {[], %{}} end, name: __MODULE__)
     schedule_update()
     agent
   end
 
-  def get do
-    Agent.get(__MODULE__, fn stats -> stats end)
+  def get_stats do
+    Agent.get(__MODULE__, fn {_, stats} -> stats end)
+  end
+
+  def get_peers do
+    Agent.get(__MODULE__, fn {peers, _} -> peers end)
   end
 
   def schedule_update do
@@ -31,8 +35,9 @@ defmodule Pleroma.Stats do
       where: p.local == ^true,
       where: fragment("?->'object'->>'type' = ?", p.data, ^"Note")
     status_count = Repo.aggregate(status_query, :count, :id)
+    user_count = Repo.aggregate(User.local_user_query, :count, :id)
     Agent.update(__MODULE__, fn _ ->
-      %{peers: peers, domain_count: domain_count, status_count: status_count}
+      {peers, %{domain_count: domain_count, status_count: status_count, user_count: user_count}}
     end)
   end
 end
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index 6ca7a6076..0615ac11a 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -93,8 +93,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   @instance Application.get_env(:pleroma, :instance)
 
   def masto_instance(conn, _params) do
-    user_count = Repo.aggregate(User.local_user_query, :count, :id)
-    %{domain_count: domain_count, status_count: status_count} = Stats.get()
     response = %{
       uri: Web.base_url,
       title: Keyword.get(@instance, :name),
@@ -104,11 +102,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
       urls: %{
         streaming_api: String.replace(Web.base_url, ["http","https"], "wss")
       },
-      stats: %{
-        status_count: status_count,
-        user_count: user_count,
-        domain_count: domain_count
-      },
+      stats: Stats.get_stats,
       max_toot_chars: Keyword.get(@instance, :limit)
     }
 
@@ -116,8 +110,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def peers(conn, _params) do
-    %{peers: peers} = Stats.get()
-    json(conn, peers)
+    json(conn, Stats.get_peers)
   end
 
   defp mastodonized_emoji do

From 6e1cb86166d82a4ac4e5fb2ecf8955b18a7ab466 Mon Sep 17 00:00:00 2001
From: eal <eal@waifu.club>
Date: Sun, 14 Jan 2018 08:28:35 +0200
Subject: [PATCH 05/16] Fix instance test.

---
 test/web/mastodon_api/mastodon_api_controller_test.exs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index 79ad671d9..93b29dfae 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -586,11 +586,14 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
     {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
 
+    Pleroma.Stats.update_stats()
+
     conn = conn
     |> get("/api/v1/instance")
 
     assert result = json_response(conn, 200)
 
     assert result["stats"]["user_count"] == 2
+    assert result["stats"]["status_count"] == 1
   end
 end

From 048f61d7f86b41018214e76649c3c8588bc05a54 Mon Sep 17 00:00:00 2001
From: Hakaba Hitoyo <hakabahitoyo@yahoo.co.jp>
Date: Sun, 14 Jan 2018 08:54:28 +0000
Subject: [PATCH 06/16] #95 Correct prod.exs

---
 config/prod.exs | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/config/prod.exs b/config/prod.exs
index 732bab2b0..8522c67da 100644
--- a/config/prod.exs
+++ b/config/prod.exs
@@ -14,9 +14,12 @@ use Mix.Config
 # manifest is generated by the mix phoenix.digest task
 # which you typically run after static files are built.
 config :pleroma, Pleroma.Web.Endpoint,
-  on_init: {Pleroma.Web.Endpoint, :load_from_system_env, []},
-  url: [host: "example.com", port: 80],
-  cache_static_manifest: "priv/static/cache_manifest.json"
+  http: [port: 4000],
+  protocol: "http",
+  debug_errors: true,
+  code_reloader: true,
+  check_origin: false,
+  watchers: []
 
 # Do not print debug messages in production
 config :logger, level: :info

From aceef36e5675253b32b0be4322b055e98a0154e7 Mon Sep 17 00:00:00 2001
From: Hakaba Hitoyo <hakabahitoyo@yahoo.co.jp>
Date: Sun, 14 Jan 2018 10:57:25 +0000
Subject: [PATCH 07/16] Correct pleroma.nginx

---
 installation/pleroma.nginx | 2 --
 1 file changed, 2 deletions(-)

diff --git a/installation/pleroma.nginx b/installation/pleroma.nginx
index 4e88a426d..92ed8f32e 100644
--- a/installation/pleroma.nginx
+++ b/installation/pleroma.nginx
@@ -34,6 +34,4 @@ server {
         proxy_pass http://localhost:4000;
     }
 
-    include snippets/well-known.conf;
-
 }

From 14b086eec22486d1efc8248f5f157696e7621e5b Mon Sep 17 00:00:00 2001
From: eal <eal@waifu.club>
Date: Mon, 15 Jan 2018 22:18:17 +0200
Subject: [PATCH 08/16] Add a default profile picture and banner.

This removes the placehold.it dependency.
---
 lib/pleroma/user.ex                           |   4 +--
 .../web/mastodon_api/views/account_view.ex    |   6 +----
 .../web/twitter_api/views/user_view.ex        |   2 +-
 priv/static/static/avi.png                    | Bin 0 -> 3604 bytes
 priv/static/static/banner.png                 | Bin 0 -> 1293 bytes
 test/web/mastodon_api/account_view_test.exs   |   8 +++---
 test/web/ostatus/user_representer_test.exs    |   1 +
 test/web/twitter_api/views/user_view_test.exs |  23 ++++++++++++------
 8 files changed, 24 insertions(+), 20 deletions(-)
 create mode 100644 priv/static/static/avi.png
 create mode 100644 priv/static/static/banner.png

diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 09bcf0cb4..6ba2b165c 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -29,14 +29,14 @@ defmodule Pleroma.User do
   def avatar_url(user) do
     case user.avatar do
       %{"url" => [%{"href" => href} | _]} -> href
-      _ -> "https://placehold.it/48x48"
+      _ -> "#{Web.base_url()}/static/avi.png"
     end
   end
 
   def banner_url(user) do
     case user.info["banner"] do
       %{"url" => [%{"href" => href} | _]} -> href
-      _ -> nil
+      _ -> "#{Web.base_url()}/static/banner.png"
     end
   end
 
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index 1d5918988..d2a4dd366 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -5,19 +5,15 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
   alias Pleroma.Web.CommonAPI.Utils
   alias Pleroma.Web.MediaProxy
 
-  defp image_url(%{"url" => [ %{ "href" => href } | _ ]}), do: href
-  defp image_url(_), do: nil
-
   def render("accounts.json", %{users: users} = opts) do
     render_many(users, AccountView, "account.json", opts)
   end
 
   def render("account.json", %{user: user}) do
     image = User.avatar_url(user) |> MediaProxy.url()
+    header = User.banner_url(user) |> MediaProxy.url()
     user_info = User.user_info(user)
 
-    header = (image_url(user.info["banner"]) || "https://placehold.it/700x335") |> MediaProxy.url()
-
     %{
       id: to_string(user.id),
       username: hd(String.split(user.nickname, "@")),
diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex
index cc6b450fb..1b995f42f 100644
--- a/lib/pleroma/web/twitter_api/views/user_view.ex
+++ b/lib/pleroma/web/twitter_api/views/user_view.ex
@@ -45,7 +45,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
       "screen_name" => user.nickname,
       "statuses_count" => user_info[:note_count],
       "statusnet_profile_url" => user.ap_id,
-      "cover_photo" => image_url(user.info["banner"]) |> MediaProxy.url(),
+      "cover_photo" => User.banner_url(user) |> MediaProxy.url(),
       "background_image" => image_url(user.info["background"]) |> MediaProxy.url(),
     }
 
diff --git a/priv/static/static/avi.png b/priv/static/static/avi.png
new file mode 100644
index 0000000000000000000000000000000000000000..336fd15ef331c88a057ce05ce49ae237b4e7bfbf
GIT binary patch
literal 3604
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
F{{dsjz|jBz

literal 0
HcmV?d00001

diff --git a/priv/static/static/banner.png b/priv/static/static/banner.png
new file mode 100644
index 0000000000000000000000000000000000000000..467c075d64667cdb67bac4c20ee06153bb28a774
GIT binary patch
literal 1293
zcmeAS@N?(olHy`uVBq!ia0y~yVA{jL!06Ax1Qby)>#_q<oCO|{#S9GG!XV7ZFl&wk
zP*65AB%;JQKQ}iuuLQ_tU~n!<O)N=GQ7F$W$xv|j^bJVSOJ!$ZV43FW;uunK>+Lm1
zK_HL8@yq!nH)lbX4bl(ereBt2V3<CMfx&>6p&^rj!H1b4L5hLlG6Ta5HW+olgn?lh
zBa#XXg-{h33ZX_JOhi?I%}$UCpw*}fp{_!496|-E;}DiXeSuI2b@!<A!BIUL`k*8|
gFo|cvXomCG`ErA0_3f=M|AUGyPgg&ebxsLQ0Kkg+N&o-=

literal 0
HcmV?d00001

diff --git a/test/web/mastodon_api/account_view_test.exs b/test/web/mastodon_api/account_view_test.exs
index eccfe0b36..061fc2693 100644
--- a/test/web/mastodon_api/account_view_test.exs
+++ b/test/web/mastodon_api/account_view_test.exs
@@ -19,10 +19,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
       statuses_count: 5,
       note: user.bio,
       url: user.ap_id,
-      avatar: "https://placehold.it/48x48",
-      avatar_static: "https://placehold.it/48x48",
-      header: "https://placehold.it/700x335",
-      header_static: "https://placehold.it/700x335",
+      avatar: "http://localhost:4001/static/avi.png",
+      avatar_static: "http://localhost:4001/static/avi.png",
+      header: "http://localhost:4001/static/banner.png",
+      header_static: "http://localhost:4001/static/banner.png",
       source: %{
         note: "",
         privacy: "public",
diff --git a/test/web/ostatus/user_representer_test.exs b/test/web/ostatus/user_representer_test.exs
index d5d70f5c6..b22420379 100644
--- a/test/web/ostatus/user_representer_test.exs
+++ b/test/web/ostatus/user_representer_test.exs
@@ -21,6 +21,7 @@ defmodule Pleroma.Web.OStatus.UserRepresenterTest do
     <summary>#{user.bio}</summary>
     <name>#{user.nickname}</name>
     <link rel="avatar" href="#{User.avatar_url(user)}" />
+    <link rel="header" href="#{User.banner_url(user)}" />
     """
 
     assert clean(res) == clean(expected)
diff --git a/test/web/twitter_api/views/user_view_test.exs b/test/web/twitter_api/views/user_view_test.exs
index 753e41d20..3f84e4116 100644
--- a/test/web/twitter_api/views/user_view_test.exs
+++ b/test/web/twitter_api/views/user_view_test.exs
@@ -33,7 +33,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
     {:ok, user} = User.update_follower_count(user)
     Cachex.set(:user_cache, "user_info:#{user.id}", User.user_info(Repo.get!(User, user.id)))
 
-    image = "https://placehold.it/48x48"
+    image = "http://localhost:4001/static/avi.png"
+    banner = "http://localhost:4001/static/banner.png"
 
     represented = %{
       "id" => user.id,
@@ -54,7 +55,7 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
       "statusnet_blocking" => false,
       "rights" => %{},
       "statusnet_profile_url" => user.ap_id,
-      "cover_photo" => nil,
+      "cover_photo" => banner,
       "background_image" => nil
     }
 
@@ -64,7 +65,9 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
   test "A user for a given other follower", %{user: user} do
     {:ok, follower} = UserBuilder.insert(%{following: [User.ap_followers(user)]})
     {:ok, user} = User.update_follower_count(user)
-    image = "https://placehold.it/48x48"
+    image = "http://localhost:4001/static/avi.png"
+    banner = "http://localhost:4001/static/banner.png"
+
     represented = %{
       "id" => user.id,
       "name" => user.name,
@@ -84,7 +87,7 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
       "statusnet_blocking" => false,
       "rights" => %{},
       "statusnet_profile_url" => user.ap_id,
-      "cover_photo" => nil,
+      "cover_photo" => banner,
       "background_image" => nil
     }
 
@@ -95,7 +98,9 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
     follower = insert(:user)
     {:ok, follower} = User.follow(follower, user)
     {:ok, user} = User.update_follower_count(user)
-    image = "https://placehold.it/48x48"
+    image = "http://localhost:4001/static/avi.png"
+    banner = "http://localhost:4001/static/banner.png"
+
     represented = %{
       "id" => follower.id,
       "name" => follower.name,
@@ -115,7 +120,7 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
       "statusnet_blocking" => false,
       "rights" => %{},
       "statusnet_profile_url" => follower.ap_id,
-      "cover_photo" => nil,
+      "cover_photo" => banner,
       "background_image" => nil
     }
 
@@ -126,7 +131,9 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
     user = insert(:user)
     blocker = insert(:user)
     User.block(blocker, user)
-    image = "https://placehold.it/48x48"
+    image = "http://localhost:4001/static/avi.png"
+    banner = "http://localhost:4001/static/banner.png"
+
     represented = %{
       "id" => user.id,
       "name" => user.name,
@@ -146,7 +153,7 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
       "statusnet_blocking" => true,
       "rights" => %{},
       "statusnet_profile_url" => user.ap_id,
-      "cover_photo" => nil,
+      "cover_photo" => banner,
       "background_image" => nil
     }
 

From b3e7d7ae6d4ab4b871ecf18706461945fd148a1b Mon Sep 17 00:00:00 2001
From: eal <eal@waifu.club>
Date: Tue, 16 Jan 2018 15:31:03 +0200
Subject: [PATCH 09/16] Fetch external profile in the background.

---
 lib/pleroma/web/twitter_api/twitter_api.ex | 10 ++++++----
 test/web/twitter_api/twitter_api_test.exs  |  2 +-
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index d04a81cd4..faecebde0 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -316,10 +316,12 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
 
   def get_external_profile(for_user, uri) do
     with {:ok, %User{} = user} <- OStatus.find_or_make_user(uri) do
-      with url <- user.info["topic"],
-           {:ok, %{body: body}} <- @httpoison.get(url, [], follow_redirect: true, timeout: 10000, recv_timeout: 20000) do
-        OStatus.handle_incoming(body)
-      end
+      spawn(fn ->
+        with url <- user.info["topic"],
+             {:ok, %{body: body}} <- @httpoison.get(url, [], follow_redirect: true, timeout: 10000, recv_timeout: 20000) do
+          OStatus.handle_incoming(body)
+        end
+      end)
       {:ok, UserView.render("show.json", %{user: user, for: for_user})}
     else _e ->
         {:error, "Couldn't find user"}
diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs
index 823ba3913..ac62880d5 100644
--- a/test/web/twitter_api/twitter_api_test.exs
+++ b/test/web/twitter_api/twitter_api_test.exs
@@ -404,7 +404,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
       assert represented["id"] == UserView.render("show.json", %{user: remote, for: user})["id"]
 
       # Also fetches the feed.
-      assert Activity.get_create_activity_by_object_ap_id("tag:mastodon.social,2017-04-05:objectId=1641750:objectType=Status")
+      # assert Activity.get_create_activity_by_object_ap_id("tag:mastodon.social,2017-04-05:objectId=1641750:objectType=Status")
     end
   end
 end

From bc689740f09ee8201982455988bf5f4ccb02fe57 Mon Sep 17 00:00:00 2001
From: eal <eal@waifu.club>
Date: Tue, 16 Jan 2018 02:17:55 +0200
Subject: [PATCH 10/16] Add remote follow path to webfinger.

---
 lib/pleroma/web/ostatus/ostatus.ex       | 4 ++++
 lib/pleroma/web/web_finger/web_finger.ex | 3 ++-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex
index 745539b3e..e65cab3ed 100644
--- a/lib/pleroma/web/ostatus/ostatus.ex
+++ b/lib/pleroma/web/ostatus/ostatus.ex
@@ -22,6 +22,10 @@ defmodule Pleroma.Web.OStatus do
     "#{user.ap_id}/salmon"
   end
 
+  def remote_follow_path do
+    "#{Web.base_url}/ostatus_subscribe?acct={uri}"
+  end
+
   def handle_incoming(xml_string) do
     with doc when doc != :error <- parse_document(xml_string) do
       entries = :xmerl_xpath.string('//entry', doc)
diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex
index 026d2f98b..4ae3eab59 100644
--- a/lib/pleroma/web/web_finger/web_finger.ex
+++ b/lib/pleroma/web/web_finger/web_finger.ex
@@ -44,7 +44,8 @@ defmodule Pleroma.Web.WebFinger do
         {:Link, %{rel: "http://schemas.google.com/g/2010#updates-from", type: "application/atom+xml", href: OStatus.feed_path(user)}},
         {:Link, %{rel: "http://webfinger.net/rel/profile-page", type: "text/html", href: user.ap_id}},
         {:Link, %{rel: "salmon", href: OStatus.salmon_path(user)}},
-        {:Link, %{rel: "magic-public-key", href: "data:application/magic-public-key,#{magic_key}"}}
+        {:Link, %{rel: "magic-public-key", href: "data:application/magic-public-key,#{magic_key}"}},
+        {:Link, %{rel: "http://ostatus.org/schema/1.0/subscribe", template: OStatus.remote_follow_path()}}
       ]
     }
     |> XmlBuilder.to_doc

From 47e8c8db05dbe1f9d0ad7790be9ae9ed40f4e909 Mon Sep 17 00:00:00 2001
From: eal <eal@waifu.club>
Date: Thu, 18 Jan 2018 00:22:08 +0200
Subject: [PATCH 11/16] Add remote follow pages.

---
 lib/pleroma/web/router.ex                     | 13 +++++
 .../twitter_api/util/follow.html.eex          | 11 +++++
 .../twitter_api/util/follow_login.html.eex    | 14 ++++++
 .../twitter_api/util/followed.html.eex        |  6 +++
 .../controllers/util_controller.ex            | 48 +++++++++++++++++++
 5 files changed, 92 insertions(+)
 create mode 100644 lib/pleroma/web/templates/twitter_api/util/follow.html.eex
 create mode 100644 lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex
 create mode 100644 lib/pleroma/web/templates/twitter_api/util/followed.html.eex

diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 09104fc86..63dbd6245 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -28,6 +28,13 @@ defmodule Pleroma.Web.Router do
     plug Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1, optional: true}
   end
 
+  pipeline :pleroma_html do
+    plug :accepts, ["html"]
+    plug :fetch_session
+    plug Pleroma.Plugs.OAuthPlug
+    plug Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1, optional: true}
+  end
+
   pipeline :well_known do
     plug :accepts, ["xml", "xrd+xml"]
   end
@@ -51,6 +58,12 @@ defmodule Pleroma.Web.Router do
     get "/emoji", UtilController, :emoji
   end
 
+  scope "/", Pleroma.Web.TwitterAPI do
+    pipe_through :pleroma_html
+    get "/ostatus_subscribe", UtilController, :remote_follow
+    post "/ostatus_subscribe", UtilController, :do_remote_follow
+  end
+
   scope "/api/pleroma", Pleroma.Web.TwitterAPI do
     pipe_through :authenticated_api
     post "/follow_import", UtilController, :follow_import
diff --git a/lib/pleroma/web/templates/twitter_api/util/follow.html.eex b/lib/pleroma/web/templates/twitter_api/util/follow.html.eex
new file mode 100644
index 000000000..06359fa6c
--- /dev/null
+++ b/lib/pleroma/web/templates/twitter_api/util/follow.html.eex
@@ -0,0 +1,11 @@
+<%= 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
new file mode 100644
index 000000000..4e3a2be67
--- /dev/null
+++ b/lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex
@@ -0,0 +1,14 @@
+<%= 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/templates/twitter_api/util/followed.html.eex b/lib/pleroma/web/templates/twitter_api/util/followed.html.eex
new file mode 100644
index 000000000..da473d502
--- /dev/null
+++ b/lib/pleroma/web/templates/twitter_api/util/followed.html.eex
@@ -0,0 +1,6 @@
+<%= if @error do %>
+<p>Error following account</p>
+<% else %>
+<h2>Account followed!</h2>
+<% end %>
+
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index 9d5654995..a1d56e3ab 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -2,6 +2,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
   use Pleroma.Web, :controller
   require Logger
   alias Pleroma.Web
+  alias Pleroma.Web.OStatus
+  alias Comeonin.Pbkdf2
   alias Pleroma.Formatter
   alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.{Repo, PasswordResetToken, User}
@@ -30,6 +32,52 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
     json(conn, "ok")
   end
 
+  def remote_follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do
+    {err, followee} = OStatus.find_or_make_user(acct)
+    avatar = User.avatar_url(followee)
+    name = followee.nickname
+    id = followee.id
+
+    if !!user do
+      conn
+      |> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id})
+    else
+      conn
+      |> render("follow_login.html", %{error: false, acct: acct, avatar: avatar, name: name, id: id})
+    end
+  end
+
+  def do_remote_follow(conn, %{"authorization" => %{"name" => username, "password" => password, "id" => id}}) do
+    followee = Repo.get(User, id)
+    avatar = User.avatar_url(followee)
+    name = followee.nickname
+    with %User{} = user <- User.get_cached_by_nickname(username),
+         true <- Pbkdf2.checkpw(password, user.password_hash),
+           %User{} = followed <- Repo.get(User, id),
+         {:ok, follower} <- User.follow(user, followee),
+         {:ok, _activity} <- ActivityPub.follow(follower, followee) do
+      conn
+      |> render("followed.html", %{error: false})
+    else
+      _e ->
+        conn
+        |> render("follow_login.html", %{error: "Wrong username or password", id: id, name: name, avatar: avatar})
+    end
+  end
+  def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do
+    with %User{} = followee <- Repo.get(User, id),
+         {:ok, follower} <- User.follow(user, followee),
+         {:ok, _activity} <- ActivityPub.follow(follower, followee) do
+      conn
+      |> render("followed.html", %{error: false})
+    else
+      e ->
+        Logger.debug("Remote follow failed with error #{inspect e}")
+      conn
+      |> render("followed.html", %{error: inspect(e)})
+    end
+  end
+
   @instance Application.get_env(:pleroma, :instance)
   def config(conn, _params) do
     case get_format(conn) do

From fb5aa34092cf8aa04b3b7001e81cf1585ee0041a Mon Sep 17 00:00:00 2001
From: eal <eal@waifu.club>
Date: Thu, 18 Jan 2018 03:42:09 +0200
Subject: [PATCH 12/16] Revert "Add remote follow path to webfinger."

This reverts commit bc689740f09ee8201982455988bf5f4ccb02fe57.
---
 lib/pleroma/web/ostatus/ostatus.ex       | 4 ----
 lib/pleroma/web/web_finger/web_finger.ex | 3 +--
 2 files changed, 1 insertion(+), 6 deletions(-)

diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex
index e65cab3ed..745539b3e 100644
--- a/lib/pleroma/web/ostatus/ostatus.ex
+++ b/lib/pleroma/web/ostatus/ostatus.ex
@@ -22,10 +22,6 @@ defmodule Pleroma.Web.OStatus do
     "#{user.ap_id}/salmon"
   end
 
-  def remote_follow_path do
-    "#{Web.base_url}/ostatus_subscribe?acct={uri}"
-  end
-
   def handle_incoming(xml_string) do
     with doc when doc != :error <- parse_document(xml_string) do
       entries = :xmerl_xpath.string('//entry', doc)
diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex
index 4ae3eab59..026d2f98b 100644
--- a/lib/pleroma/web/web_finger/web_finger.ex
+++ b/lib/pleroma/web/web_finger/web_finger.ex
@@ -44,8 +44,7 @@ defmodule Pleroma.Web.WebFinger do
         {:Link, %{rel: "http://schemas.google.com/g/2010#updates-from", type: "application/atom+xml", href: OStatus.feed_path(user)}},
         {:Link, %{rel: "http://webfinger.net/rel/profile-page", type: "text/html", href: user.ap_id}},
         {:Link, %{rel: "salmon", href: OStatus.salmon_path(user)}},
-        {:Link, %{rel: "magic-public-key", href: "data:application/magic-public-key,#{magic_key}"}},
-        {:Link, %{rel: "http://ostatus.org/schema/1.0/subscribe", template: OStatus.remote_follow_path()}}
+        {:Link, %{rel: "magic-public-key", href: "data:application/magic-public-key,#{magic_key}"}}
       ]
     }
     |> XmlBuilder.to_doc

From b259b4e4d1dc27528b99744fffabfb05c676ec3f Mon Sep 17 00:00:00 2001
From: eal <eal@waifu.club>
Date: Thu, 18 Jan 2018 03:42:18 +0200
Subject: [PATCH 13/16] Revert "Add remote follow pages."

This reverts commit 47e8c8db05dbe1f9d0ad7790be9ae9ed40f4e909.
---
 lib/pleroma/web/router.ex                     | 13 -----
 .../twitter_api/util/follow.html.eex          | 11 -----
 .../twitter_api/util/follow_login.html.eex    | 14 ------
 .../twitter_api/util/followed.html.eex        |  6 ---
 .../controllers/util_controller.ex            | 48 -------------------
 5 files changed, 92 deletions(-)
 delete mode 100644 lib/pleroma/web/templates/twitter_api/util/follow.html.eex
 delete mode 100644 lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex
 delete mode 100644 lib/pleroma/web/templates/twitter_api/util/followed.html.eex

diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 63dbd6245..09104fc86 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -28,13 +28,6 @@ defmodule Pleroma.Web.Router do
     plug Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1, optional: true}
   end
 
-  pipeline :pleroma_html do
-    plug :accepts, ["html"]
-    plug :fetch_session
-    plug Pleroma.Plugs.OAuthPlug
-    plug Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1, optional: true}
-  end
-
   pipeline :well_known do
     plug :accepts, ["xml", "xrd+xml"]
   end
@@ -58,12 +51,6 @@ defmodule Pleroma.Web.Router do
     get "/emoji", UtilController, :emoji
   end
 
-  scope "/", Pleroma.Web.TwitterAPI do
-    pipe_through :pleroma_html
-    get "/ostatus_subscribe", UtilController, :remote_follow
-    post "/ostatus_subscribe", UtilController, :do_remote_follow
-  end
-
   scope "/api/pleroma", Pleroma.Web.TwitterAPI do
     pipe_through :authenticated_api
     post "/follow_import", UtilController, :follow_import
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
index 06359fa6c..000000000
--- a/lib/pleroma/web/templates/twitter_api/util/follow.html.eex
+++ /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
index 4e3a2be67..000000000
--- a/lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex
+++ /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/templates/twitter_api/util/followed.html.eex b/lib/pleroma/web/templates/twitter_api/util/followed.html.eex
deleted file mode 100644
index da473d502..000000000
--- a/lib/pleroma/web/templates/twitter_api/util/followed.html.eex
+++ /dev/null
@@ -1,6 +0,0 @@
-<%= if @error do %>
-<p>Error following account</p>
-<% else %>
-<h2>Account followed!</h2>
-<% end %>
-
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index a1d56e3ab..9d5654995 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -2,8 +2,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
   use Pleroma.Web, :controller
   require Logger
   alias Pleroma.Web
-  alias Pleroma.Web.OStatus
-  alias Comeonin.Pbkdf2
   alias Pleroma.Formatter
   alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.{Repo, PasswordResetToken, User}
@@ -32,52 +30,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
     json(conn, "ok")
   end
 
-  def remote_follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do
-    {err, followee} = OStatus.find_or_make_user(acct)
-    avatar = User.avatar_url(followee)
-    name = followee.nickname
-    id = followee.id
-
-    if !!user do
-      conn
-      |> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id})
-    else
-      conn
-      |> render("follow_login.html", %{error: false, acct: acct, avatar: avatar, name: name, id: id})
-    end
-  end
-
-  def do_remote_follow(conn, %{"authorization" => %{"name" => username, "password" => password, "id" => id}}) do
-    followee = Repo.get(User, id)
-    avatar = User.avatar_url(followee)
-    name = followee.nickname
-    with %User{} = user <- User.get_cached_by_nickname(username),
-         true <- Pbkdf2.checkpw(password, user.password_hash),
-           %User{} = followed <- Repo.get(User, id),
-         {:ok, follower} <- User.follow(user, followee),
-         {:ok, _activity} <- ActivityPub.follow(follower, followee) do
-      conn
-      |> render("followed.html", %{error: false})
-    else
-      _e ->
-        conn
-        |> render("follow_login.html", %{error: "Wrong username or password", id: id, name: name, avatar: avatar})
-    end
-  end
-  def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do
-    with %User{} = followee <- Repo.get(User, id),
-         {:ok, follower} <- User.follow(user, followee),
-         {:ok, _activity} <- ActivityPub.follow(follower, followee) do
-      conn
-      |> render("followed.html", %{error: false})
-    else
-      e ->
-        Logger.debug("Remote follow failed with error #{inspect e}")
-      conn
-      |> render("followed.html", %{error: inspect(e)})
-    end
-  end
-
   @instance Application.get_env(:pleroma, :instance)
   def config(conn, _params) do
     case get_format(conn) do

From 57d413e65541f47a3c303be88c0ac6d4bfed33a9 Mon Sep 17 00:00:00 2001
From: eal <eal@waifu.club>
Date: Thu, 18 Jan 2018 18:42:32 +0200
Subject: [PATCH 14/16] Revert "Revert "Add remote follow path to webfinger.""

This reverts commit fb5aa34092cf8aa04b3b7001e81cf1585ee0041a.
---
 lib/pleroma/web/ostatus/ostatus.ex       | 4 ++++
 lib/pleroma/web/web_finger/web_finger.ex | 3 ++-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex
index 745539b3e..e65cab3ed 100644
--- a/lib/pleroma/web/ostatus/ostatus.ex
+++ b/lib/pleroma/web/ostatus/ostatus.ex
@@ -22,6 +22,10 @@ defmodule Pleroma.Web.OStatus do
     "#{user.ap_id}/salmon"
   end
 
+  def remote_follow_path do
+    "#{Web.base_url}/ostatus_subscribe?acct={uri}"
+  end
+
   def handle_incoming(xml_string) do
     with doc when doc != :error <- parse_document(xml_string) do
       entries = :xmerl_xpath.string('//entry', doc)
diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex
index 026d2f98b..4ae3eab59 100644
--- a/lib/pleroma/web/web_finger/web_finger.ex
+++ b/lib/pleroma/web/web_finger/web_finger.ex
@@ -44,7 +44,8 @@ defmodule Pleroma.Web.WebFinger do
         {:Link, %{rel: "http://schemas.google.com/g/2010#updates-from", type: "application/atom+xml", href: OStatus.feed_path(user)}},
         {:Link, %{rel: "http://webfinger.net/rel/profile-page", type: "text/html", href: user.ap_id}},
         {:Link, %{rel: "salmon", href: OStatus.salmon_path(user)}},
-        {:Link, %{rel: "magic-public-key", href: "data:application/magic-public-key,#{magic_key}"}}
+        {:Link, %{rel: "magic-public-key", href: "data:application/magic-public-key,#{magic_key}"}},
+        {:Link, %{rel: "http://ostatus.org/schema/1.0/subscribe", template: OStatus.remote_follow_path()}}
       ]
     }
     |> XmlBuilder.to_doc

From beb13bf3a9b207119d70bb817ff1ea92f17a11be Mon Sep 17 00:00:00 2001
From: eal <eal@waifu.club>
Date: Thu, 18 Jan 2018 18:42:44 +0200
Subject: [PATCH 15/16] Revert "Revert "Add remote follow pages.""

This reverts commit b259b4e4d1dc27528b99744fffabfb05c676ec3f.
---
 lib/pleroma/web/router.ex                     | 13 +++++
 .../twitter_api/util/follow.html.eex          | 11 +++++
 .../twitter_api/util/follow_login.html.eex    | 14 ++++++
 .../twitter_api/util/followed.html.eex        |  6 +++
 .../controllers/util_controller.ex            | 48 +++++++++++++++++++
 5 files changed, 92 insertions(+)
 create mode 100644 lib/pleroma/web/templates/twitter_api/util/follow.html.eex
 create mode 100644 lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex
 create mode 100644 lib/pleroma/web/templates/twitter_api/util/followed.html.eex

diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 09104fc86..63dbd6245 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -28,6 +28,13 @@ defmodule Pleroma.Web.Router do
     plug Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1, optional: true}
   end
 
+  pipeline :pleroma_html do
+    plug :accepts, ["html"]
+    plug :fetch_session
+    plug Pleroma.Plugs.OAuthPlug
+    plug Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1, optional: true}
+  end
+
   pipeline :well_known do
     plug :accepts, ["xml", "xrd+xml"]
   end
@@ -51,6 +58,12 @@ defmodule Pleroma.Web.Router do
     get "/emoji", UtilController, :emoji
   end
 
+  scope "/", Pleroma.Web.TwitterAPI do
+    pipe_through :pleroma_html
+    get "/ostatus_subscribe", UtilController, :remote_follow
+    post "/ostatus_subscribe", UtilController, :do_remote_follow
+  end
+
   scope "/api/pleroma", Pleroma.Web.TwitterAPI do
     pipe_through :authenticated_api
     post "/follow_import", UtilController, :follow_import
diff --git a/lib/pleroma/web/templates/twitter_api/util/follow.html.eex b/lib/pleroma/web/templates/twitter_api/util/follow.html.eex
new file mode 100644
index 000000000..06359fa6c
--- /dev/null
+++ b/lib/pleroma/web/templates/twitter_api/util/follow.html.eex
@@ -0,0 +1,11 @@
+<%= 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
new file mode 100644
index 000000000..4e3a2be67
--- /dev/null
+++ b/lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex
@@ -0,0 +1,14 @@
+<%= 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/templates/twitter_api/util/followed.html.eex b/lib/pleroma/web/templates/twitter_api/util/followed.html.eex
new file mode 100644
index 000000000..da473d502
--- /dev/null
+++ b/lib/pleroma/web/templates/twitter_api/util/followed.html.eex
@@ -0,0 +1,6 @@
+<%= if @error do %>
+<p>Error following account</p>
+<% else %>
+<h2>Account followed!</h2>
+<% end %>
+
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index 9d5654995..a1d56e3ab 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -2,6 +2,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
   use Pleroma.Web, :controller
   require Logger
   alias Pleroma.Web
+  alias Pleroma.Web.OStatus
+  alias Comeonin.Pbkdf2
   alias Pleroma.Formatter
   alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.{Repo, PasswordResetToken, User}
@@ -30,6 +32,52 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
     json(conn, "ok")
   end
 
+  def remote_follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do
+    {err, followee} = OStatus.find_or_make_user(acct)
+    avatar = User.avatar_url(followee)
+    name = followee.nickname
+    id = followee.id
+
+    if !!user do
+      conn
+      |> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id})
+    else
+      conn
+      |> render("follow_login.html", %{error: false, acct: acct, avatar: avatar, name: name, id: id})
+    end
+  end
+
+  def do_remote_follow(conn, %{"authorization" => %{"name" => username, "password" => password, "id" => id}}) do
+    followee = Repo.get(User, id)
+    avatar = User.avatar_url(followee)
+    name = followee.nickname
+    with %User{} = user <- User.get_cached_by_nickname(username),
+         true <- Pbkdf2.checkpw(password, user.password_hash),
+           %User{} = followed <- Repo.get(User, id),
+         {:ok, follower} <- User.follow(user, followee),
+         {:ok, _activity} <- ActivityPub.follow(follower, followee) do
+      conn
+      |> render("followed.html", %{error: false})
+    else
+      _e ->
+        conn
+        |> render("follow_login.html", %{error: "Wrong username or password", id: id, name: name, avatar: avatar})
+    end
+  end
+  def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do
+    with %User{} = followee <- Repo.get(User, id),
+         {:ok, follower} <- User.follow(user, followee),
+         {:ok, _activity} <- ActivityPub.follow(follower, followee) do
+      conn
+      |> render("followed.html", %{error: false})
+    else
+      e ->
+        Logger.debug("Remote follow failed with error #{inspect e}")
+      conn
+      |> render("followed.html", %{error: inspect(e)})
+    end
+  end
+
   @instance Application.get_env(:pleroma, :instance)
   def config(conn, _params) do
     case get_format(conn) do

From 0f722a8c223c1953c9c9fb45e73cc9ace92839e2 Mon Sep 17 00:00:00 2001
From: Roger Braun <roger@rogerbraun.net>
Date: Sat, 20 Jan 2018 18:38:30 +0100
Subject: [PATCH 16/16] Stats: Make less crashy and improve query.

---
 lib/pleroma/stats.ex | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/lib/pleroma/stats.ex b/lib/pleroma/stats.ex
index 938e5c343..0484f1a2d 100644
--- a/lib/pleroma/stats.ex
+++ b/lib/pleroma/stats.ex
@@ -5,7 +5,7 @@ defmodule Pleroma.Stats do
 
   def start_link do
     agent = Agent.start_link(fn -> {[], %{}} end, name: __MODULE__)
-    schedule_update()
+    spawn(fn -> schedule_update() end)
     agent
   end
 
@@ -18,23 +18,22 @@ defmodule Pleroma.Stats do
   end
 
   def schedule_update do
-    update_stats()
     spawn(fn ->
       Process.sleep(1000 * 60 * 60 * 1) # 1 hour
       schedule_update()
     end)
+    update_stats()
   end
 
   def update_stats do
     peers = from(u in Pleroma.User,
-      select: fragment("?->'host'", u.info),
+      select: fragment("distinct ?->'host'", u.info),
       where: u.local != ^true)
-    |> Repo.all() |> Enum.uniq()
+    |> Repo.all()
     domain_count = Enum.count(peers)
-    status_query = from p in Activity,
-      where: p.local == ^true,
-      where: fragment("?->'object'->>'type' = ?", p.data, ^"Note")
-    status_count = Repo.aggregate(status_query, :count, :id)
+    status_query = from(u in User.local_user_query,
+      select: fragment("sum((?->>'note_count')::int)", u.info))
+    status_count = Repo.one(status_query) |> IO.inspect
     user_count = Repo.aggregate(User.local_user_query, :count, :id)
     Agent.update(__MODULE__, fn _ ->
       {peers, %{domain_count: domain_count, status_count: status_count, user_count: user_count}}