diff --git a/js/src/graphql/statistics.ts b/js/src/graphql/statistics.ts
index 4fd8ff843..e229eafce 100644
--- a/js/src/graphql/statistics.ts
+++ b/js/src/graphql/statistics.ts
@@ -5,8 +5,13 @@ export const STATISTICS = gql`
statistics {
numberOfUsers
numberOfEvents
+ numberOfLocalEvents
numberOfComments
+ numberOfLocalComments
numberOfGroups
+ numberOfLocalGroups
+ numberOfInstanceFollowings
+ numberOfInstanceFollowers
}
}
`;
diff --git a/js/src/types/statistics.model.ts b/js/src/types/statistics.model.ts
index 3d8629341..e4a92996f 100644
--- a/js/src/types/statistics.model.ts
+++ b/js/src/types/statistics.model.ts
@@ -1,6 +1,11 @@
export interface IStatistics {
numberOfUsers: number;
numberOfEvents: number;
+ numberOfLocalEvents: number;
numberOfComments: number;
+ numberOfLocalComments: number;
numberOfGroups: number;
+ numberOfLocalGroups: number;
+ numberOfInstanceFollowings: number;
+ numberOfInstanceFollowers: number;
}
diff --git a/js/src/views/About/AboutInstance.vue b/js/src/views/About/AboutInstance.vue
index ad30b08cf..175bca407 100644
--- a/js/src/views/About/AboutInstance.vue
+++ b/js/src/views/About/AboutInstance.vue
@@ -14,13 +14,13 @@
{{ statistics.numberOfUsers }}
- {{ statistics.numberOfGroups }}
+ {{ statistics.numberOfLocalGroups }}
- {{ statistics.numberOfEvents }}
+ {{ statistics.numberOfLocalEvents }}
- {{ statistics.numberOfComments }}
+ {{ statistics.numberOfLocalComments }}
@@ -140,7 +140,7 @@ section {
.statistics {
display: grid;
grid-template-columns: repeat(auto-fit, 150px);
- grid-template-rows: repeat(2, 1fr);
+ gap: 2rem 0;
p {
text-align: right;
padding: 0 15px;
@@ -157,6 +157,9 @@ section {
}
}
.contact {
+ h4 {
+ font-weight: bold;
+ }
p {
width: 200px;
white-space: nowrap;
diff --git a/lib/graphql/resolvers/statistics.ex b/lib/graphql/resolvers/statistics.ex
index 3fdafeafc..c451cde40 100644
--- a/lib/graphql/resolvers/statistics.ex
+++ b/lib/graphql/resolvers/statistics.ex
@@ -12,9 +12,14 @@ defmodule Mobilizon.GraphQL.Resolvers.Statistics do
{:ok,
%{
number_of_users: StatisticsModule.get_cached_value(:local_users),
- number_of_events: StatisticsModule.get_cached_value(:local_events),
- number_of_comments: StatisticsModule.get_cached_value(:local_comments),
- number_of_groups: StatisticsModule.get_cached_value(:local_groups)
+ number_of_events: StatisticsModule.get_cached_value(:federation_events),
+ number_of_local_events: StatisticsModule.get_cached_value(:local_events),
+ number_of_comments: StatisticsModule.get_cached_value(:federation_comments),
+ number_of_local_comments: StatisticsModule.get_cached_value(:local_comments),
+ number_of_groups: StatisticsModule.get_cached_value(:federation_groups),
+ number_of_local_groups: StatisticsModule.get_cached_value(:local_groups),
+ number_of_instance_followings: StatisticsModule.get_cached_value(:instance_followings),
+ number_of_instance_followers: StatisticsModule.get_cached_value(:instance_followers)
}}
end
end
diff --git a/lib/graphql/schema/statistics.ex b/lib/graphql/schema/statistics.ex
index f3c19810b..58d3b27bf 100644
--- a/lib/graphql/schema/statistics.ex
+++ b/lib/graphql/schema/statistics.ex
@@ -10,9 +10,20 @@ defmodule Mobilizon.GraphQL.Schema.StatisticsType do
object :statistics do
# Instance name
field(:number_of_users, :integer, description: "The number of local users")
- field(:number_of_events, :integer, description: "The number of local events")
- field(:number_of_comments, :integer, description: "The number of local comments")
- field(:number_of_groups, :integer, description: "The number of local groups")
+ field(:number_of_events, :integer, description: "The total number of events")
+ field(:number_of_local_events, :integer, description: "The number of local events")
+ field(:number_of_comments, :integer, description: "The total number of comments")
+ field(:number_of_local_comments, :integer, description: "The number of local events")
+ field(:number_of_groups, :integer, description: "The total number of groups")
+ field(:number_of_local_groups, :integer, description: "The number of local groups")
+
+ field(:number_of_instance_followers, :integer,
+ description: "The number of this instance's followers"
+ )
+
+ field(:number_of_instance_followings, :integer,
+ description: "The number of instances this instance follows"
+ )
end
object :statistics_queries do
diff --git a/lib/mobilizon/actors/actors.ex b/lib/mobilizon/actors/actors.ex
index 75b55882b..c78f4c582 100644
--- a/lib/mobilizon/actors/actors.ex
+++ b/lib/mobilizon/actors/actors.ex
@@ -1076,6 +1076,17 @@ defmodule Mobilizon.Actors do
|> Page.build_page(page, limit)
end
+ @doc """
+ Returns the number of followers for an actor
+ """
+ @spec count_followers_for_actor(Actor.t()) :: integer()
+ def count_followers_for_actor(%Actor{id: actor_id}) do
+ actor_id
+ |> follower_for_actor_query()
+ |> where(approved: true)
+ |> Repo.aggregate(:count)
+ end
+
@doc """
Returns the list of followings for an actor.
If actor A follows actor B and C, actor A's followings are B and C.
@@ -1087,6 +1098,17 @@ defmodule Mobilizon.Actors do
|> Repo.all()
end
+ @doc """
+ Returns the number of followings for an actor
+ """
+ @spec count_followings_for_actor(Actor.t()) :: integer()
+ def count_followings_for_actor(%Actor{id: actor_id}) do
+ actor_id
+ |> followings_for_actor_query()
+ |> where(approved: true)
+ |> Repo.aggregate(:count)
+ end
+
@doc """
Returns the list of external followings for an actor.
"""
diff --git a/lib/service/statistics/statistics.ex b/lib/service/statistics/statistics.ex
index c3a0efaf1..42998b968 100644
--- a/lib/service/statistics/statistics.ex
+++ b/lib/service/statistics/statistics.ex
@@ -4,6 +4,7 @@ defmodule Mobilizon.Service.Statistics do
"""
alias Mobilizon.{Actors, Discussions, Events, Users}
+ alias Mobilizon.Federation.ActivityPub.Relay
def get_cached_value(key) do
case Cachex.fetch(:statistics, key, fn key ->
@@ -44,4 +45,14 @@ defmodule Mobilizon.Service.Statistics do
defp create_cache(:federation_groups) do
Actors.count_groups()
end
+
+ defp create_cache(:instance_followers) do
+ relay_actor = Relay.get_actor()
+ Actors.count_followers_for_actor(relay_actor)
+ end
+
+ defp create_cache(:instance_followings) do
+ relay_actor = Relay.get_actor()
+ Actors.count_followings_for_actor(relay_actor)
+ end
end
diff --git a/test/graphql/resolvers/statistics_test.exs b/test/graphql/resolvers/statistics_test.exs
new file mode 100644
index 000000000..3b6e155da
--- /dev/null
+++ b/test/graphql/resolvers/statistics_test.exs
@@ -0,0 +1,46 @@
+defmodule Mobilizon.GraphQL.Resolvers.StatisticsTest do
+ use Mobilizon.Web.ConnCase
+
+ import Mobilizon.Factory
+
+ alias Mobilizon.GraphQL.AbsintheHelpers
+
+ describe "statistics resolver" do
+ @statistics_query """
+ query {
+ statistics {
+ numberOfUsers
+ numberOfEvents
+ numberOfLocalEvents
+ numberOfComments
+ numberOfLocalComments
+ numberOfGroups
+ numberOfLocalGroups
+ numberOfInstanceFollowings
+ numberOfInstanceFollowers
+ }
+ }
+ """
+
+ test "get statistics", %{conn: conn} do
+ Cachex.clear(:statistics)
+ insert(:event)
+ insert(:comment)
+ insert(:group)
+ actor = insert(:actor, user: nil, domain: "toto.tld")
+ insert(:event, organizer_actor: actor, local: false)
+
+ res = AbsintheHelpers.graphql_query(conn, query: @statistics_query)
+
+ assert res["data"]["statistics"]["numberOfUsers"] == 6
+ assert res["data"]["statistics"]["numberOfLocalEvents"] == 2
+ assert res["data"]["statistics"]["numberOfEvents"] == 3
+ assert res["data"]["statistics"]["numberOfLocalComments"] == 1
+ assert res["data"]["statistics"]["numberOfLocalGroups"] == 1
+
+ insert(:event)
+ # We keep the value in cache
+ assert res["data"]["statistics"]["numberOfLocalEvents"] == 2
+ end
+ end
+end