From c8046e1080e613766812e89b1ed28af45580cc33 Mon Sep 17 00:00:00 2001
From: rinpatch <rinpatch@sdf.org>
Date: Mon, 16 Dec 2019 00:48:49 +0300
Subject: [PATCH 01/12] tests: Replace 2 second sleep with offseting updated_at

---
 test/conversation/participation_test.exs | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/test/conversation/participation_test.exs b/test/conversation/participation_test.exs
index 9b2c97963..88dc32198 100644
--- a/test/conversation/participation_test.exs
+++ b/test/conversation/participation_test.exs
@@ -5,7 +5,9 @@
 defmodule Pleroma.Conversation.ParticipationTest do
   use Pleroma.DataCase
   import Pleroma.Factory
+  alias Pleroma.Conversation
   alias Pleroma.Conversation.Participation
+  alias Pleroma.Repo
   alias Pleroma.User
   alias Pleroma.Web.CommonAPI
 
@@ -97,8 +99,10 @@ defmodule Pleroma.Conversation.ParticipationTest do
 
     assert participation.user_id == user.id
     assert participation.conversation_id == conversation.id
-
+    
+    # Needed because updated_at is accurate down to a second
     :timer.sleep(1000)
+
     # Creating again returns the same participation
     {:ok, %Participation{} = participation_two} =
       Participation.create_for_user_and_conversation(user, conversation)
@@ -150,9 +154,7 @@ defmodule Pleroma.Conversation.ParticipationTest do
   test "gets all the participations for a user, ordered by updated at descending" do
     user = insert(:user)
     {:ok, activity_one} = CommonAPI.post(user, %{"status" => "x", "visibility" => "direct"})
-    :timer.sleep(1000)
     {:ok, activity_two} = CommonAPI.post(user, %{"status" => "x", "visibility" => "direct"})
-    :timer.sleep(1000)
 
     {:ok, activity_three} =
       CommonAPI.post(user, %{
@@ -161,6 +163,17 @@ defmodule Pleroma.Conversation.ParticipationTest do
         "in_reply_to_status_id" => activity_one.id
       })
 
+    # Offset participations because the accuracy of updated_at is down to a second
+
+    for {activity, offset} <- [{activity_two, 1}, {activity_three, 2}] do
+      conversation = Conversation.get_for_ap_id(activity.data["context"])
+      participation = Participation.for_user_and_conversation(user, conversation)
+      updated_at = NaiveDateTime.add(Map.get(participation, :updated_at), offset)
+
+      Ecto.Changeset.change(participation, %{updated_at: updated_at})
+      |> Repo.update!()
+    end
+
     assert [participation_one, participation_two] = Participation.for_user(user)
 
     object2 = Pleroma.Object.normalize(activity_two)

From 814a99c80f11835ce3fd5d75c38f418662430b04 Mon Sep 17 00:00:00 2001
From: rinpatch <rinpatch@sdf.org>
Date: Mon, 16 Dec 2019 00:50:39 +0300
Subject: [PATCH 02/12] tests: remove a useless 3 second sleep

the ids favs use are accurate down to a microsecond, there is no need
for it
---
 test/web/activity_pub/activity_pub_test.exs | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index ad1fb6d02..1520c8a9b 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -1639,13 +1639,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
 
       {:ok, _, _} = CommonAPI.favorite(a4.id, user)
       {:ok, _, _} = CommonAPI.favorite(a3.id, other_user)
-      Process.sleep(1000)
       {:ok, _, _} = CommonAPI.favorite(a3.id, user)
       {:ok, _, _} = CommonAPI.favorite(a5.id, other_user)
-      Process.sleep(1000)
       {:ok, _, _} = CommonAPI.favorite(a5.id, user)
       {:ok, _, _} = CommonAPI.favorite(a4.id, other_user)
-      Process.sleep(1000)
       {:ok, _, _} = CommonAPI.favorite(a1.id, user)
       {:ok, _, _} = CommonAPI.favorite(a1.id, other_user)
       result = ActivityPub.fetch_favourites(user)

From 137a3d220bba01e9cacd8007fa030c69830cc9aa Mon Sep 17 00:00:00 2001
From: rinpatch <rinpatch@sdf.org>
Date: Mon, 16 Dec 2019 00:51:59 +0300
Subject: [PATCH 03/12] tests: remove a useless 1 second sleep

there is no need to wait for the task to finish, it will be deleted
when the transaction is aborted anyway.
---
 test/web/twitter_api/util_controller_test.exs | 2 --
 1 file changed, 2 deletions(-)

diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs
index 734cd2211..43299e147 100644
--- a/test/web/twitter_api/util_controller_test.exs
+++ b/test/web/twitter_api/util_controller_test.exs
@@ -898,8 +898,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
         |> post("/api/pleroma/delete_account", %{"password" => "test"})
 
       assert json_response(conn, 200) == %{"status" => "success"}
-      # Wait a second for the started task to end
-      :timer.sleep(1000)
     end
   end
 end

From 54029fe21271e7d4396699ee297f2910cd6fbbdc Mon Sep 17 00:00:00 2001
From: rinpatch <rinpatch@sdf.org>
Date: Mon, 16 Dec 2019 01:03:13 +0300
Subject: [PATCH 04/12] tests: remove a useless sleep in rate limiter tests

It was used to check that authenticated and unauthenticated users have
different limits. Instead of sleeping a super low limit for
unauthenticated users was set, preventing them from doing 5 requests in
the first place.
---
 test/conversation/participation_test.exs |  2 +-
 test/plugs/rate_limiter_test.exs         | 14 ++------------
 2 files changed, 3 insertions(+), 13 deletions(-)

diff --git a/test/conversation/participation_test.exs b/test/conversation/participation_test.exs
index 88dc32198..ba81c0d4b 100644
--- a/test/conversation/participation_test.exs
+++ b/test/conversation/participation_test.exs
@@ -99,7 +99,7 @@ defmodule Pleroma.Conversation.ParticipationTest do
 
     assert participation.user_id == user.id
     assert participation.conversation_id == conversation.id
-    
+
     # Needed because updated_at is accurate down to a second
     :timer.sleep(1000)
 
diff --git a/test/plugs/rate_limiter_test.exs b/test/plugs/rate_limiter_test.exs
index 49f63c424..78f1ea9e4 100644
--- a/test/plugs/rate_limiter_test.exs
+++ b/test/plugs/rate_limiter_test.exs
@@ -145,9 +145,9 @@ defmodule Pleroma.Plugs.RateLimiterTest do
     test "can have limits seperate from unauthenticated connections" do
       limiter_name = :test_authenticated
 
-      scale = 1000
+      scale = 50
       limit = 5
-      Pleroma.Config.put([:rate_limit, limiter_name], [{1, 10}, {scale, limit}])
+      Pleroma.Config.put([:rate_limit, limiter_name], [{1000, 1}, {scale, limit}])
 
       opts = RateLimiter.init(name: limiter_name)
 
@@ -164,16 +164,6 @@ defmodule Pleroma.Plugs.RateLimiterTest do
 
       assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests)
       assert conn.halted
-
-      Process.sleep(1550)
-
-      conn = conn(:get, "/") |> assign(:user, user)
-      conn = RateLimiter.call(conn, opts)
-      assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, opts)
-
-      refute conn.status == Plug.Conn.Status.code(:too_many_requests)
-      refute conn.resp_body
-      refute conn.halted
     end
 
     test "diffrerent users are counted independently" do

From 6ffbfdeeb2fc5ce7c2bf3a58950f5bf1f9a31e6f Mon Sep 17 00:00:00 2001
From: rinpatch <rinpatch@sdf.org>
Date: Mon, 16 Dec 2019 01:22:01 +0300
Subject: [PATCH 05/12] tests: significantly reduce streamer timeout

there is no reason IPC between two processes on the same node should
take 4 seconds
---
 test/web/streamer/streamer_test.exs | 42 ++++++++++++++++-------------
 1 file changed, 23 insertions(+), 19 deletions(-)

diff --git a/test/web/streamer/streamer_test.exs b/test/web/streamer/streamer_test.exs
index 8911c46b1..b07a7373f 100644
--- a/test/web/streamer/streamer_test.exs
+++ b/test/web/streamer/streamer_test.exs
@@ -16,6 +16,10 @@ defmodule Pleroma.Web.StreamerTest do
   alias Pleroma.Web.Streamer.Worker
 
   @moduletag needs_streamer: true, capture_log: true
+
+  @streamer_timeout 150
+  @streamer_start_wait 10
+
   clear_config_all([:instance, :skip_thread_containment])
 
   describe "user streams" do
@@ -28,7 +32,7 @@ defmodule Pleroma.Web.StreamerTest do
     test "it sends notify to in the 'user' stream", %{user: user, notify: notify} do
       task =
         Task.async(fn ->
-          assert_receive {:text, _}, 4_000
+          assert_receive {:text, _}, @streamer_timeout
         end)
 
       Streamer.add_socket(
@@ -43,7 +47,7 @@ defmodule Pleroma.Web.StreamerTest do
     test "it sends notify to in the 'user:notification' stream", %{user: user, notify: notify} do
       task =
         Task.async(fn ->
-          assert_receive {:text, _}, 4_000
+          assert_receive {:text, _}, @streamer_timeout
         end)
 
       Streamer.add_socket(
@@ -61,7 +65,7 @@ defmodule Pleroma.Web.StreamerTest do
       blocked = insert(:user)
       {:ok, _user_relationship} = User.block(user, blocked)
 
-      task = Task.async(fn -> refute_receive {:text, _}, 4_000 end)
+      task = Task.async(fn -> refute_receive {:text, _}, @streamer_timeout end)
 
       Streamer.add_socket(
         "user:notification",
@@ -79,7 +83,7 @@ defmodule Pleroma.Web.StreamerTest do
       user: user
     } do
       user2 = insert(:user)
-      task = Task.async(fn -> refute_receive {:text, _}, 4_000 end)
+      task = Task.async(fn -> refute_receive {:text, _}, @streamer_timeout end)
 
       Streamer.add_socket(
         "user:notification",
@@ -97,7 +101,7 @@ defmodule Pleroma.Web.StreamerTest do
       user: user
     } do
       user2 = insert(:user, %{ap_id: "https://hecking-lewd-place.com/user/meanie"})
-      task = Task.async(fn -> refute_receive {:text, _}, 4_000 end)
+      task = Task.async(fn -> refute_receive {:text, _}, @streamer_timeout end)
 
       Streamer.add_socket(
         "user:notification",
@@ -116,7 +120,9 @@ defmodule Pleroma.Web.StreamerTest do
       user: user
     } do
       user2 = insert(:user)
-      task = Task.async(fn -> assert_receive {:text, _}, 4_000 end)
+      task = Task.async(fn -> assert_receive {:text, _}, @streamer_timeout end)
+      
+      Process.sleep(@streamer_start_wait)
 
       Streamer.add_socket(
         "user:notification",
@@ -137,7 +143,7 @@ defmodule Pleroma.Web.StreamerTest do
 
     task =
       Task.async(fn ->
-        assert_receive {:text, _}, 4_000
+        assert_receive {:text, _}, @streamer_timeout 
       end)
 
     fake_socket = %StreamerSocket{
@@ -164,7 +170,7 @@ defmodule Pleroma.Web.StreamerTest do
           }
           |> Jason.encode!()
 
-        assert_receive {:text, received_event}, 4_000
+        assert_receive {:text, received_event}, @streamer_timeout
         assert received_event == expected_event
       end)
 
@@ -458,9 +464,7 @@ defmodule Pleroma.Web.StreamerTest do
 
     {:ok, activity} = CommonAPI.add_mute(user2, activity)
 
-    task = Task.async(fn -> refute_receive {:text, _}, 4_000 end)
-
-    Process.sleep(4000)
+    task = Task.async(fn -> refute_receive {:text, _}, @streamer_timeout end)
 
     Streamer.add_socket(
       "user",
@@ -482,7 +486,7 @@ defmodule Pleroma.Web.StreamerTest do
 
       task =
         Task.async(fn ->
-          assert_receive {:text, received_event}, 4_000
+          assert_receive {:text, received_event}, @streamer_timeout
 
           assert %{"event" => "conversation", "payload" => received_payload} =
                    Jason.decode!(received_event)
@@ -518,13 +522,13 @@ defmodule Pleroma.Web.StreamerTest do
 
       task =
         Task.async(fn ->
-          assert_receive {:text, received_event}, 4_000
+          assert_receive {:text, received_event}, @streamer_timeout
           assert %{"event" => "delete", "payload" => _} = Jason.decode!(received_event)
 
-          refute_receive {:text, _}, 4_000
+          refute_receive {:text, _}, @streamer_timeout
         end)
 
-      Process.sleep(1000)
+      Process.sleep(@streamer_start_wait)
 
       Streamer.add_socket(
         "direct",
@@ -555,11 +559,11 @@ defmodule Pleroma.Web.StreamerTest do
 
       task =
         Task.async(fn ->
-          assert_receive {:text, received_event}, 4_000
+
+          assert_receive {:text, received_event}, @streamer_timeout
           assert %{"event" => "delete", "payload" => _} = Jason.decode!(received_event)
 
-          assert_receive {:text, received_event}, 4_000
-
+          assert_receive {:text, received_event}, @streamer_timeout
           assert %{"event" => "conversation", "payload" => received_payload} =
                    Jason.decode!(received_event)
 
@@ -567,7 +571,7 @@ defmodule Pleroma.Web.StreamerTest do
           assert last_status["id"] == to_string(create_activity.id)
         end)
 
-      Process.sleep(1000)
+      Process.sleep(@streamer_start_wait)
 
       Streamer.add_socket(
         "direct",

From eae65e3216cb43f97e58ace7e0a57919332de8b8 Mon Sep 17 00:00:00 2001
From: rinpatch <rinpatch@sdf.org>
Date: Mon, 16 Dec 2019 01:37:33 +0300
Subject: [PATCH 06/12] formatting

---
 test/web/streamer/streamer_test.exs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/test/web/streamer/streamer_test.exs b/test/web/streamer/streamer_test.exs
index b07a7373f..7166d6f0b 100644
--- a/test/web/streamer/streamer_test.exs
+++ b/test/web/streamer/streamer_test.exs
@@ -121,7 +121,7 @@ defmodule Pleroma.Web.StreamerTest do
     } do
       user2 = insert(:user)
       task = Task.async(fn -> assert_receive {:text, _}, @streamer_timeout end)
-      
+
       Process.sleep(@streamer_start_wait)
 
       Streamer.add_socket(
@@ -143,7 +143,7 @@ defmodule Pleroma.Web.StreamerTest do
 
     task =
       Task.async(fn ->
-        assert_receive {:text, _}, @streamer_timeout 
+        assert_receive {:text, _}, @streamer_timeout
       end)
 
     fake_socket = %StreamerSocket{
@@ -559,11 +559,11 @@ defmodule Pleroma.Web.StreamerTest do
 
       task =
         Task.async(fn ->
-
           assert_receive {:text, received_event}, @streamer_timeout
           assert %{"event" => "delete", "payload" => _} = Jason.decode!(received_event)
 
           assert_receive {:text, received_event}, @streamer_timeout
+
           assert %{"event" => "conversation", "payload" => received_payload} =
                    Jason.decode!(received_event)
 

From 82c62c5028f517ded121b46b9806053989defdc2 Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn <egor@kislitsyn.com>
Date: Mon, 16 Dec 2019 15:32:33 +0700
Subject: [PATCH 07/12] Add default endpoint to Pleroma.Captcha.Kocaptcha

---
 config/test.exs                  | 2 --
 lib/pleroma/captcha/kocaptcha.ex | 4 +++-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/config/test.exs b/config/test.exs
index b48b89c8f..d52ced612 100644
--- a/config/test.exs
+++ b/config/test.exs
@@ -95,8 +95,6 @@ config :joken, default_signer: "yU8uHKq+yyAkZ11Hx//jcdacWc8yQ1bxAAGrplzB0Zwwjkp3
 
 config :pleroma, Pleroma.ReverseProxy.Client, Pleroma.ReverseProxy.ClientMock
 
-config :pleroma, Pleroma.Captcha.Kocaptcha, endpoint: "https://captcha.kotobank.ch"
-
 if File.exists?("./config/test.secret.exs") do
   import_config "test.secret.exs"
 else
diff --git a/lib/pleroma/captcha/kocaptcha.ex b/lib/pleroma/captcha/kocaptcha.ex
index 4e1a07c59..a3128decb 100644
--- a/lib/pleroma/captcha/kocaptcha.ex
+++ b/lib/pleroma/captcha/kocaptcha.ex
@@ -5,11 +5,13 @@
 defmodule Pleroma.Captcha.Kocaptcha do
   import Pleroma.Web.Gettext
   alias Pleroma.Captcha.Service
+
   @behaviour Service
+  @default_endpoint "https://captcha.kotobank.ch"
 
   @impl Service
   def new do
-    endpoint = Pleroma.Config.get!([__MODULE__, :endpoint])
+    endpoint = Pleroma.Config.get([__MODULE__, :endpoint], @default_endpoint)
 
     case Tesla.get(endpoint <> "/new") do
       {:error, _} ->

From 8d242f52d4bf44a012603fb2cc6fe4dd9b282ef8 Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn <egor@kislitsyn.com>
Date: Mon, 16 Dec 2019 19:33:51 +0700
Subject: [PATCH 08/12] Revert "Add default endpoint to
 Pleroma.Captcha.Kocaptcha"

This reverts commit 82c62c5028f517ded121b46b9806053989defdc2.
---
 config/test.exs                  | 2 ++
 lib/pleroma/captcha/kocaptcha.ex | 4 +---
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/config/test.exs b/config/test.exs
index d52ced612..b48b89c8f 100644
--- a/config/test.exs
+++ b/config/test.exs
@@ -95,6 +95,8 @@ config :joken, default_signer: "yU8uHKq+yyAkZ11Hx//jcdacWc8yQ1bxAAGrplzB0Zwwjkp3
 
 config :pleroma, Pleroma.ReverseProxy.Client, Pleroma.ReverseProxy.ClientMock
 
+config :pleroma, Pleroma.Captcha.Kocaptcha, endpoint: "https://captcha.kotobank.ch"
+
 if File.exists?("./config/test.secret.exs") do
   import_config "test.secret.exs"
 else
diff --git a/lib/pleroma/captcha/kocaptcha.ex b/lib/pleroma/captcha/kocaptcha.ex
index a3128decb..4e1a07c59 100644
--- a/lib/pleroma/captcha/kocaptcha.ex
+++ b/lib/pleroma/captcha/kocaptcha.ex
@@ -5,13 +5,11 @@
 defmodule Pleroma.Captcha.Kocaptcha do
   import Pleroma.Web.Gettext
   alias Pleroma.Captcha.Service
-
   @behaviour Service
-  @default_endpoint "https://captcha.kotobank.ch"
 
   @impl Service
   def new do
-    endpoint = Pleroma.Config.get([__MODULE__, :endpoint], @default_endpoint)
+    endpoint = Pleroma.Config.get!([__MODULE__, :endpoint])
 
     case Tesla.get(endpoint <> "/new") do
       {:error, _} ->

From fc484e5ce67117389ce9e2cce22ab1944a759242 Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn <egor@kislitsyn.com>
Date: Mon, 16 Dec 2019 19:35:10 +0700
Subject: [PATCH 09/12] Add Kocaptcha endpoint to config.exs

---
 config/config.exs | 2 ++
 config/test.exs   | 2 --
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/config/config.exs b/config/config.exs
index 370ddd855..47098858b 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -70,6 +70,8 @@ config :pleroma, Pleroma.Captcha,
   seconds_valid: 60,
   method: Pleroma.Captcha.Native
 
+config :pleroma, Pleroma.Captcha.Kocaptcha, endpoint: "https://captcha.kotobank.ch"
+
 config :pleroma, :hackney_pools,
   federation: [
     max_connections: 50,
diff --git a/config/test.exs b/config/test.exs
index b48b89c8f..d52ced612 100644
--- a/config/test.exs
+++ b/config/test.exs
@@ -95,8 +95,6 @@ config :joken, default_signer: "yU8uHKq+yyAkZ11Hx//jcdacWc8yQ1bxAAGrplzB0Zwwjkp3
 
 config :pleroma, Pleroma.ReverseProxy.Client, Pleroma.ReverseProxy.ClientMock
 
-config :pleroma, Pleroma.Captcha.Kocaptcha, endpoint: "https://captcha.kotobank.ch"
-
 if File.exists?("./config/test.secret.exs") do
   import_config "test.secret.exs"
 else

From 8f79f433bcf6e901d67987a613e909c0b507aa65 Mon Sep 17 00:00:00 2001
From: Egor Kislitsyn <egor@kislitsyn.com>
Date: Tue, 17 Dec 2019 13:34:07 +0700
Subject: [PATCH 10/12] Hide follower counter when hiding is activated

---
 lib/pleroma/web/activity_pub/views/user_view.ex | 8 +++++++-
 test/web/activity_pub/views/user_view_test.exs  | 2 +-
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex
index 9059aa634..350c4391d 100644
--- a/lib/pleroma/web/activity_pub/views/user_view.ex
+++ b/lib/pleroma/web/activity_pub/views/user_view.ex
@@ -201,7 +201,6 @@ defmodule Pleroma.Web.ActivityPub.UserView do
     %{
       "id" => "#{user.ap_id}/followers",
       "type" => "OrderedCollection",
-      "totalItems" => total,
       "first" =>
         if showing_items do
           collection(followers, "#{user.ap_id}/followers", 1, showing_items, total)
@@ -209,6 +208,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
           "#{user.ap_id}/followers?page=1"
         end
     }
+    |> maybe_put_total_items(showing_count, total)
     |> Map.merge(Utils.make_json_ld_header())
   end
 
@@ -251,6 +251,12 @@ defmodule Pleroma.Web.ActivityPub.UserView do
     |> Map.merge(Utils.make_json_ld_header())
   end
 
+  defp maybe_put_total_items(map, false, _total), do: map
+
+  defp maybe_put_total_items(map, true, total) do
+    Map.put(map, "totalItems", total)
+  end
+
   def collection(collection, iri, page, show_items \\ true, total \\ nil) do
     offset = (page - 1) * 10
     items = Enum.slice(collection, offset, 10)
diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs
index 3299be2d5..8374b8d23 100644
--- a/test/web/activity_pub/views/user_view_test.exs
+++ b/test/web/activity_pub/views/user_view_test.exs
@@ -126,7 +126,7 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do
       {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user)
       assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user})
       user = Map.merge(user, %{hide_followers_count: true, hide_followers: true})
-      assert %{"totalItems" => 0} = UserView.render("followers.json", %{user: user})
+      refute UserView.render("followers.json", %{user: user}) |> Map.has_key?("totalItems")
     end
 
     test "sets correct totalItems when followers are hidden but the follower counter is not" do

From d2f1c4f658a8c995716aee3876cb46a0f48f99cb Mon Sep 17 00:00:00 2001
From: Thomas Citharel <tcit@tcit.fr>
Date: Tue, 17 Dec 2019 16:16:21 +0100
Subject: [PATCH 11/12] Add ActivityPub Object Event type support

Adds Event support in the same way Video objects are handled, with the
name of the object as message header.

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
---
 lib/pleroma/web/activity_pub/transmogrifier.ex |  2 +-
 lib/pleroma/web/activity_pub/utils.ex          | 11 ++++++++++-
 .../web/mastodon_api/views/status_view.ex      |  3 ++-
 .../twitter_api/controllers/util_controller.ex |  3 ++-
 .../tesla_mock/mobilizon.org-event.json        |  1 +
 .../tesla_mock/mobilizon.org-user.json         |  1 +
 test/object/fetcher_test.exs                   |  9 +++++++++
 test/support/http_request_mock.ex              | 18 ++++++++++++++++++
 .../mastodon_api/views/status_view_test.exs    | 15 +++++++++++++++
 9 files changed, 59 insertions(+), 4 deletions(-)
 create mode 100644 test/fixtures/tesla_mock/mobilizon.org-event.json
 create mode 100644 test/fixtures/tesla_mock/mobilizon.org-user.json

diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index ecba27bef..3fa789d53 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -397,7 +397,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
         %{"type" => "Create", "object" => %{"type" => objtype} = object} = data,
         options
       )
-      when objtype in ["Article", "Note", "Video", "Page", "Question", "Answer"] do
+      when objtype in ["Article", "Event", "Note", "Video", "Page", "Question", "Answer"] do
     actor = Containment.get_actor(data)
 
     data =
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index e87d09134..db7084246 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -22,7 +22,16 @@ defmodule Pleroma.Web.ActivityPub.Utils do
   require Logger
   require Pleroma.Constants
 
-  @supported_object_types ["Article", "Note", "Video", "Page", "Question", "Answer", "Audio"]
+  @supported_object_types [
+    "Article",
+    "Note",
+    "Event",
+    "Video",
+    "Page",
+    "Question",
+    "Answer",
+    "Audio"
+  ]
   @strip_status_report_states ~w(closed resolved)
   @supported_report_states ~w(open closed resolved)
   @valid_visibilities ~w(public unlisted private direct)
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index a0257dfa6..e9590224b 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -421,7 +421,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
     end
   end
 
-  def render_content(%{data: %{"type" => "Video"}} = object) do
+  def render_content(%{data: %{"type" => object_type}} = object)
+      when object_type in ["Video", "Event"] do
     with name when not is_nil(name) and name != "" <- object.data["name"] do
       "<p><a href=\"#{object.data["id"]}\">#{name}</a></p>#{object.data["content"]}"
     else
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index 2305bb413..799dd17ae 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -104,7 +104,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
 
   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", "Note", "Video", "Page", "Question"] ->
+      {:ok, %{"type" => type}}
+      when type in ["Article", "Event", "Note", "Video", "Page", "Question"] ->
         true
 
       _ ->
diff --git a/test/fixtures/tesla_mock/mobilizon.org-event.json b/test/fixtures/tesla_mock/mobilizon.org-event.json
new file mode 100644
index 000000000..7411cf817
--- /dev/null
+++ b/test/fixtures/tesla_mock/mobilizon.org-event.json
@@ -0,0 +1 @@
+{"@context":["https://www.w3.org/ns/activitystreams","https://litepub.social/litepub/context.jsonld",{"GeoCoordinates":"sc:GeoCoordinates","Hashtag":"as:Hashtag","Place":"sc:Place","PostalAddress":"sc:PostalAddress","address":{"@id":"sc:address","@type":"sc:PostalAddress"},"addressCountry":"sc:addressCountry","addressLocality":"sc:addressLocality","addressRegion":"sc:addressRegion","category":"sc:category","commentsEnabled":{"@id":"pt:commentsEnabled","@type":"sc:Boolean"},"geo":{"@id":"sc:geo","@type":"sc:GeoCoordinates"},"ical":"http://www.w3.org/2002/12/cal/ical#","joinMode":{"@id":"mz:joinMode","@type":"mz:joinModeType"},"joinModeType":{"@id":"mz:joinModeType","@type":"rdfs:Class"},"location":{"@id":"sc:location","@type":"sc:Place"},"maximumAttendeeCapacity":"sc:maximumAttendeeCapacity","mz":"https://joinmobilizon.org/ns#","postalCode":"sc:postalCode","pt":"https://joinpeertube.org/ns#","repliesModerationOption":{"@id":"mz:repliesModerationOption","@type":"mz:repliesModerationOptionType"},"repliesModerationOptionType":{"@id":"mz:repliesModerationOptionType","@type":"rdfs:Class"},"sc":"http://schema.org#","streetAddress":"sc:streetAddress","uuid":"sc:identifier"}],"actor":"https://mobilizon.org/@tcit","attributedTo":"https://mobilizon.org/@tcit","category":"meeting","cc":[],"commentsEnabled":true,"content":"<p>Mobilizon is now federated! 🎉</p><p></p><p>You can view this event from other instances if they are subscribed to mobilizon.org, and soon directly from Mastodon and Pleroma. It is possible that you may see some comments from other instances, including Mastodon ones, just below.</p><p></p><p>With a Mobilizon account on an instance, you may <strong>participate</strong> at events from other instances and <strong>add comments</strong> on events.</p><p></p><p>Of course, it's still <u>a work in progress</u>: if reports made from an instance on events and comments can be federated, you can't block people right now, and moderators actions are rather limited, but this <strong>will definitely get fixed over time</strong> until first stable version next year.</p><p></p><p>Anyway, if you want to come up with some feedback, head over to our forum or - if you feel you have technical skills and are familiar with it - on our Gitlab repository.</p><p></p><p>Also, to people that want to set Mobilizon themselves even though we really don't advise to do that for now, we have a little documentation but it's quite the early days and you'll probably need some help. No worries, you can chat with us on our Forum or though our Matrix channel.</p><p></p><p>Check our website for more informations and follow us on Twitter or Mastodon.</p>","endTime":"2019-12-18T14:00:00Z","ical:status":"CONFIRMED","id":"https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39","joinMode":"free","location":{"address":{"addressCountry":"France","addressLocality":"Nantes","addressRegion":"Pays de la Loire","postalCode":null,"streetAddress":" ","type":"PostalAddress"},"geo":{"latitude":-1.54939699141711,"longitude":47.21617415,"type":"GeoCoordinates"},"id":"https://mobilizon.org/address/1368fdab-1e2c-4de6-bcff-a90c84abdee1","name":"Cour du Château des Ducs de Bretagne","type":"Place"},"maximumAttendeeCapacity":0,"mediaType":"text/html","name":"Mobilizon Launching Party","published":"2019-12-17T11:33:56Z","repliesModerationOption":"allow_all","startTime":"2019-12-18T13:00:00Z","tag":[{"href":"https://mobilizon.org/tags/mobilizon","name":"#Mobilizon","type":"Hashtag"},{"href":"https://mobilizon.org/tags/federation","name":"#Federation","type":"Hashtag"},{"href":"https://mobilizon.org/tags/activitypub","name":"#ActivityPub","type":"Hashtag"},{"href":"https://mobilizon.org/tags/party","name":"#Party","type":"Hashtag"}],"to":["https://www.w3.org/ns/activitystreams#Public"],"type":"Event","updated":"2019-12-17T12:25:01Z","url":"https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39","uuid":"252d5816-00a3-4a89-a66f-15bf65c33e39"}
\ No newline at end of file
diff --git a/test/fixtures/tesla_mock/mobilizon.org-user.json b/test/fixtures/tesla_mock/mobilizon.org-user.json
new file mode 100644
index 000000000..f948ae5f0
--- /dev/null
+++ b/test/fixtures/tesla_mock/mobilizon.org-user.json
@@ -0,0 +1 @@
+{"@context":["https://www.w3.org/ns/activitystreams","https://litepub.social/litepub/context.jsonld",{"GeoCoordinates":"sc:GeoCoordinates","Hashtag":"as:Hashtag","Place":"sc:Place","PostalAddress":"sc:PostalAddress","address":{"@id":"sc:address","@type":"sc:PostalAddress"},"addressCountry":"sc:addressCountry","addressLocality":"sc:addressLocality","addressRegion":"sc:addressRegion","category":"sc:category","commentsEnabled":{"@id":"pt:commentsEnabled","@type":"sc:Boolean"},"geo":{"@id":"sc:geo","@type":"sc:GeoCoordinates"},"ical":"http://www.w3.org/2002/12/cal/ical#","joinMode":{"@id":"mz:joinMode","@type":"mz:joinModeType"},"joinModeType":{"@id":"mz:joinModeType","@type":"rdfs:Class"},"location":{"@id":"sc:location","@type":"sc:Place"},"maximumAttendeeCapacity":"sc:maximumAttendeeCapacity","mz":"https://joinmobilizon.org/ns#","postalCode":"sc:postalCode","pt":"https://joinpeertube.org/ns#","repliesModerationOption":{"@id":"mz:repliesModerationOption","@type":"mz:repliesModerationOptionType"},"repliesModerationOptionType":{"@id":"mz:repliesModerationOptionType","@type":"rdfs:Class"},"sc":"http://schema.org#","streetAddress":"sc:streetAddress","uuid":"sc:identifier"}],"endpoints":{"sharedInbox":"https://mobilizon.org/inbox"},"followers":"https://mobilizon.org/@tcit/followers","following":"https://mobilizon.org/@tcit/following","icon":{"mediaType":null,"type":"Image","url":"https://mobilizon.org/media/3a5f18c058a8193b1febfaf561f94ae8b91f85ac64c01ddf5ad7b251fb43baf5.jpg?name=profil.jpg"},"id":"https://mobilizon.org/@tcit","inbox":"https://mobilizon.org/@tcit/inbox","manuallyApprovesFollowers":false,"name":"Thomas Citharel","outbox":"https://mobilizon.org/@tcit/outbox","preferredUsername":"tcit","publicKey":{"id":"https://mobilizon.org/@tcit#main-key","owner":"https://mobilizon.org/@tcit","publicKeyPem":"-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAtzuZFviv5f12SuA0wZFMuwKS8RIlT3IjPCMLRDhiorZeV3UJ1lik\nDYO6mEh22KDXYgJtNVSYGF0Q5LJivgcvuvU+VQ048iTB1B2x0rHMr47KPByPjfVb\nKDeHt6fkHcLY0JK8UkIxW542wXAg4jX5w3gJi3pgTQrCT8VNyPbH1CaA0uW//9jc\nqzZQVFzpfdJoVOM9E3Urc/u58HC4xOptlM7+B/594ZI9drYwy5m+ZxHwlQUYCva4\n34dvwsfOGxkQyIrzXoep80EnWnFpYCLMcCiz+sEhPYxqLgNE+Cmn/6pv7SIscz6p\neVlQXIchdw+J4yl07paJDkFc6CNTCmaIHQIDAQAB\n-----END RSA PUBLIC KEY-----\n\n"},"summary":"Main profile","type":"Person","url":"https://mobilizon.org/@tcit"}
\ No newline at end of file
diff --git a/test/object/fetcher_test.exs b/test/object/fetcher_test.exs
index 9ae6b015d..2aad7a588 100644
--- a/test/object/fetcher_test.exs
+++ b/test/object/fetcher_test.exs
@@ -77,6 +77,15 @@ defmodule Pleroma.Object.FetcherTest do
       assert object
     end
 
+    test "it can fetch Mobilizon events" do
+      {:ok, object} =
+        Fetcher.fetch_object_from_id(
+          "https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39"
+        )
+
+      assert object
+    end
+
     test "it can fetch wedistribute articles" do
       {:ok, object} =
         Fetcher.fetch_object_from_id("https://wedistribute.org/wp-json/pterotype/v1/object/85810")
diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex
index e3a621f49..f43de700d 100644
--- a/test/support/http_request_mock.ex
+++ b/test/support/http_request_mock.ex
@@ -308,6 +308,24 @@ defmodule HttpRequestMock do
      }}
   end
 
+  def get("https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39", _, _,
+        Accept: "application/activity+json"
+      ) do
+    {:ok,
+     %Tesla.Env{
+       status: 200,
+       body: File.read!("test/fixtures/tesla_mock/mobilizon.org-event.json")
+     }}
+  end
+
+  def get("https://mobilizon.org/@tcit", _, _, Accept: "application/activity+json") do
+    {:ok,
+     %Tesla.Env{
+       status: 200,
+       body: File.read!("test/fixtures/tesla_mock/mobilizon.org-user.json")
+     }}
+  end
+
   def get("https://baptiste.gelez.xyz/@/BaptisteGelez", _, _, _) do
     {:ok,
      %Tesla.Env{
diff --git a/test/web/mastodon_api/views/status_view_test.exs b/test/web/mastodon_api/views/status_view_test.exs
index bdd87a79e..17b6ebcbc 100644
--- a/test/web/mastodon_api/views/status_view_test.exs
+++ b/test/web/mastodon_api/views/status_view_test.exs
@@ -394,6 +394,21 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
     assert length(represented[:media_attachments]) == 1
   end
 
+  test "a Mobilizon event" do
+    user = insert(:user)
+
+    {:ok, object} =
+      Pleroma.Object.Fetcher.fetch_object_from_id(
+        "https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39"
+      )
+
+    %Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"])
+
+    represented = StatusView.render("show.json", %{for: user, activity: activity})
+
+    assert represented[:id] == to_string(activity.id)
+  end
+
   describe "build_tags/1" do
     test "it returns a a dictionary tags" do
       object_tags = [

From 407449158fab56943da95af5172db4e464588d0e Mon Sep 17 00:00:00 2001
From: rinpatch <rinpatch@sdf.org>
Date: Tue, 17 Dec 2019 18:24:16 +0300
Subject: [PATCH 12/12] CI: Add a cache policy for test jobs and fix rum tests
 recompiling everything

---
 .gitlab-ci.yml | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 88789035d..dc85eaba2 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,13 +1,13 @@
 image: elixir:1.8.1
 
-variables:
+variables: &global_variables
   POSTGRES_DB: pleroma_test
   POSTGRES_USER: postgres
   POSTGRES_PASSWORD: postgres
   DB_HOST: postgres
   MIX_ENV: test
 
-cache:
+cache: &global_cache_policy
   key: ${CI_COMMIT_REF_SLUG}
   paths:
           - deps
@@ -46,6 +46,10 @@ benchmark:
 
 unit-testing:
   stage: test
+  cache: &testing_cache_policy
+    <<: *global_cache_policy
+    policy: pull
+
   services:
   - name: postgres:9.6
     alias: postgres
@@ -58,6 +62,7 @@ unit-testing:
 
 federated-testing:
   stage: test
+  cache: *testing_cache_policy
   services:
   - name: minibikini/postgres-with-rum:12
     alias: postgres
@@ -71,11 +76,13 @@ federated-testing:
 
 unit-testing-rum:
   stage: test
+  cache: *testing_cache_policy
   services:
   - name: minibikini/postgres-with-rum:12
     alias: postgres
     command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
   variables:
+    <<: *global_variables
     RUM_ENABLED: "true"
   script:
     - mix deps.get
@@ -86,17 +93,20 @@ unit-testing-rum:
 
 lint:
   stage: test
+  cache: *testing_cache_policy
   script:
     - mix format --check-formatted
 
 analysis:
   stage: test
+  cache: *testing_cache_policy
   script:
     - mix deps.get
     - mix credo --strict --only=warnings,todo,fixme,consistency,readability
 
 docs-deploy:
   stage: deploy
+  cache: *testing_cache_policy
   image: alpine:latest
   only:
   - stable@pleroma/pleroma