Update stats admin endpoint
authorRoman Chvanikov <chvanikoff@pm.me>
Sat, 9 May 2020 08:30:37 +0000 (11:30 +0300)
committerRoman Chvanikov <chvanikoff@pm.me>
Sat, 9 May 2020 08:30:37 +0000 (11:30 +0300)
lib/pleroma/counter_cache.ex
lib/pleroma/stats.ex
lib/pleroma/web/admin_api/admin_api_controller.ex
priv/repo/migrations/20200508092434_update_counter_cache_table.exs
test/stats_test.exs
test/web/admin_api/admin_api_controller_test.exs

index b469e7b50846da0fb64d194fd6389c8d36c1be42..a940b5e50cca97ef1605a5d81014888256b7f143 100644 (file)
@@ -40,7 +40,7 @@ defmodule Pleroma.CounterCache do
     end
   end
 
-  def get_as_map() do
+  def get_sum() do
     CounterCache
     |> select([c], %{
       "public" => sum(c.public),
@@ -49,6 +49,10 @@ defmodule Pleroma.CounterCache do
       "direct" => sum(c.direct)
     })
     |> Repo.one()
+    |> Enum.map(fn {visibility, dec_count} ->
+      {visibility, Decimal.to_integer(dec_count)}
+    end)
+    |> Enum.into(%{})
   end
 
   def set(instance, values) do
index 4e355bd5ca631546e4b0f3672caeb09f628f2dff..9a03f01db7087d1766599908748a062050b14354 100644 (file)
@@ -97,14 +97,11 @@ defmodule Pleroma.Stats do
     }
   end
 
-  def get_status_visibility_count do
-    counter_cache = CounterCache.get_as_map()
-
-    %{
-      public: counter_cache["status_visibility_public"] || 0,
-      unlisted: counter_cache["status_visibility_unlisted"] || 0,
-      private: counter_cache["status_visibility_private"] || 0,
-      direct: counter_cache["status_visibility_direct"] || 0
-    }
+  def get_status_visibility_count(instance \\ nil) do
+    if is_nil(instance) do
+      CounterCache.get_sum()
+    else
+      CounterCache.get_by_instance(instance)
+    end
   end
 end
index 9f1fd3aeb334f273577a189f460cb55229937096..4db9f4cac24394cae07e9846d3dcd03147ed69a1 100644 (file)
@@ -1122,11 +1122,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
     end
   end
 
-  def stats(conn, _) do
-    count = Stats.get_status_visibility_count()
+  def stats(conn, params) do
+    counters = Stats.get_status_visibility_count(params["instance"])
 
-    conn
-    |> json(%{"status_visibility" => count})
+    json(conn, %{"status_visibility" => counters})
   end
 
   defp errors(conn, {:error, :not_found}) do
index 81a8d6397d34b2c15e5cb7025dc311c461ee0890..3d9bfc87733401900455c746b1342434c275530c 100644 (file)
@@ -43,7 +43,8 @@ defmodule Pleroma.Repo.Migrations.UpdateCounterCacheTable do
       END IF;
       IF TG_OP = 'INSERT' THEN
         visibility_new := activity_visibility(NEW.actor, NEW.recipients, NEW.data);
-        IF NEW.data->>'type' = 'Create' THEN
+        IF NEW.data->>'type' = 'Create'
+            AND visibility_new IN ('public', 'unlisted', 'private', 'direct') THEN
           EXECUTE format('INSERT INTO "counter_cache" ("instance", %1$I) VALUES ($1, 1)
                           ON CONFLICT ("instance") DO
                           UPDATE SET %1$I = "counter_cache".%1$I + 1', visibility_new)
@@ -53,7 +54,10 @@ defmodule Pleroma.Repo.Migrations.UpdateCounterCacheTable do
       ELSIF TG_OP = 'UPDATE' THEN
         visibility_new := activity_visibility(NEW.actor, NEW.recipients, NEW.data);
         visibility_old := activity_visibility(OLD.actor, OLD.recipients, OLD.data);
-        IF (NEW.data->>'type' = 'Create') and (OLD.data->>'type' = 'Create') and visibility_new != visibility_old THEN
+        IF (NEW.data->>'type' = 'Create')
+            AND (OLD.data->>'type' = 'Create')
+            AND visibility_new != visibility_old
+            AND visibility_new IN ('public', 'unlisted', 'private', 'direct') THEN
           EXECUTE format('UPDATE "counter_cache" SET
                           %1$I = greatest("counter_cache".%1$I - 1, 0),
                           %2$I = "counter_cache".%2$I + 1
index c1aeb2c7f525871c569ab6aa8f59b93233c33102..33ed0b7dd12ab4492b75bf7132bf76e5dd8d69b4 100644 (file)
@@ -17,10 +17,11 @@ defmodule Pleroma.StatsTest do
     end
   end
 
-  describe "status visibility count" do
+  describe "status visibility sum count" do
     test "on new status" do
+      instance2 = "instance2.tld"
       user = insert(:user)
-      other_user = insert(:user)
+      other_user = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
 
       CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
 
@@ -45,24 +46,24 @@ defmodule Pleroma.StatsTest do
         })
       end)
 
-      assert %{direct: 3, private: 4, public: 1, unlisted: 2} =
+      assert %{"direct" => 3, "private" => 4, "public" => 1, "unlisted" => 2} =
                Pleroma.Stats.get_status_visibility_count()
     end
 
     test "on status delete" do
       user = insert(:user)
       {:ok, activity} = CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
-      assert %{public: 1} = Pleroma.Stats.get_status_visibility_count()
+      assert %{"public" => 1} = Pleroma.Stats.get_status_visibility_count()
       CommonAPI.delete(activity.id, user)
-      assert %{public: 0} = Pleroma.Stats.get_status_visibility_count()
+      assert %{"public" => 0} = Pleroma.Stats.get_status_visibility_count()
     end
 
     test "on status visibility update" do
       user = insert(:user)
       {:ok, activity} = CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
-      assert %{public: 1, private: 0} = Pleroma.Stats.get_status_visibility_count()
+      assert %{"public" => 1, "private" => 0} = Pleroma.Stats.get_status_visibility_count()
       {:ok, _} = CommonAPI.update_activity_scope(activity.id, %{"visibility" => "private"})
-      assert %{public: 0, private: 1} = Pleroma.Stats.get_status_visibility_count()
+      assert %{"public" => 0, "private" => 1} = Pleroma.Stats.get_status_visibility_count()
     end
 
     test "doesn't count unrelated activities" do
@@ -73,8 +74,46 @@ defmodule Pleroma.StatsTest do
       CommonAPI.favorite(other_user, activity.id)
       CommonAPI.repeat(activity.id, other_user)
 
-      assert %{direct: 0, private: 0, public: 1, unlisted: 0} =
+      assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 0} =
                Pleroma.Stats.get_status_visibility_count()
     end
   end
+
+  describe "status visibility by instance count" do
+    test "single instance" do
+      local_instance = Pleroma.Web.Endpoint.url() |> String.split("//") |> Enum.at(1)
+      instance2 = "instance2.tld"
+      user1 = insert(:user)
+      user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
+
+      CommonAPI.post(user1, %{"visibility" => "public", "status" => "hey"})
+
+      Enum.each(1..5, fn _ ->
+        CommonAPI.post(user1, %{
+          "visibility" => "unlisted",
+          "status" => "hey"
+        })
+      end)
+
+      Enum.each(1..10, fn _ ->
+        CommonAPI.post(user1, %{
+          "visibility" => "direct",
+          "status" => "hey @#{user2.nickname}"
+        })
+      end)
+
+      Enum.each(1..20, fn _ ->
+        CommonAPI.post(user2, %{
+          "visibility" => "private",
+          "status" => "hey"
+        })
+      end)
+
+      assert %{"direct" => 10, "private" => 0, "public" => 1, "unlisted" => 5} =
+               Pleroma.Stats.get_status_visibility_count(local_instance)
+
+      assert %{"direct" => 0, "private" => 20, "public" => 0, "unlisted" => 0} =
+               Pleroma.Stats.get_status_visibility_count(instance2)
+    end
+  end
 end
index 4697af50ebcb367dede7a8f9580d38feb9278682..c3de89ac0d0d0f33fcafb4b2be5dd27cc8853d4a 100644 (file)
@@ -3612,6 +3612,26 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
       assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
                response["status_visibility"]
     end
+
+    test "by instance", %{conn: conn} do
+      admin = insert(:user, is_admin: true)
+      user1 = insert(:user)
+      instance2 = "instance2.tld"
+      user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
+
+      CommonAPI.post(user1, %{"visibility" => "public", "status" => "hey"})
+      CommonAPI.post(user2, %{"visibility" => "unlisted", "status" => "hey"})
+      CommonAPI.post(user2, %{"visibility" => "private", "status" => "hey"})
+
+      response =
+        conn
+        |> assign(:user, admin)
+        |> get("/api/pleroma/admin/stats", instance: instance2)
+        |> json_response(200)
+
+      assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =
+               response["status_visibility"]
+    end
   end
 
   describe "POST /api/pleroma/admin/oauth_app" do