Expose more statistics
* differenciate local & all events/comments/groups * add instance follows/followings Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
09a0cbf3f1
commit
02eac30c9b
|
@ -5,8 +5,13 @@ export const STATISTICS = gql`
|
||||||
statistics {
|
statistics {
|
||||||
numberOfUsers
|
numberOfUsers
|
||||||
numberOfEvents
|
numberOfEvents
|
||||||
|
numberOfLocalEvents
|
||||||
numberOfComments
|
numberOfComments
|
||||||
|
numberOfLocalComments
|
||||||
numberOfGroups
|
numberOfGroups
|
||||||
|
numberOfLocalGroups
|
||||||
|
numberOfInstanceFollowings
|
||||||
|
numberOfInstanceFollowers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
export interface IStatistics {
|
export interface IStatistics {
|
||||||
numberOfUsers: number;
|
numberOfUsers: number;
|
||||||
numberOfEvents: number;
|
numberOfEvents: number;
|
||||||
|
numberOfLocalEvents: number;
|
||||||
numberOfComments: number;
|
numberOfComments: number;
|
||||||
|
numberOfLocalComments: number;
|
||||||
numberOfGroups: number;
|
numberOfGroups: number;
|
||||||
|
numberOfLocalGroups: number;
|
||||||
|
numberOfInstanceFollowings: number;
|
||||||
|
numberOfInstanceFollowers: number;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,13 @@
|
||||||
<strong slot="number">{{ statistics.numberOfUsers }}</strong>
|
<strong slot="number">{{ statistics.numberOfUsers }}</strong>
|
||||||
</i18n>
|
</i18n>
|
||||||
<i18n tag="p" path="and {number} groups">
|
<i18n tag="p" path="and {number} groups">
|
||||||
<strong slot="number">{{ statistics.numberOfGroups }}</strong>
|
<strong slot="number">{{ statistics.numberOfLocalGroups }}</strong>
|
||||||
</i18n>
|
</i18n>
|
||||||
<i18n tag="p" path="Who published {number} events">
|
<i18n tag="p" path="Who published {number} events">
|
||||||
<strong slot="number">{{ statistics.numberOfEvents }}</strong>
|
<strong slot="number">{{ statistics.numberOfLocalEvents }}</strong>
|
||||||
</i18n>
|
</i18n>
|
||||||
<i18n tag="p" path="And {number} comments">
|
<i18n tag="p" path="And {number} comments">
|
||||||
<strong slot="number">{{ statistics.numberOfComments }}</strong>
|
<strong slot="number">{{ statistics.numberOfLocalComments }}</strong>
|
||||||
</i18n>
|
</i18n>
|
||||||
</div>
|
</div>
|
||||||
<div class="column contact">
|
<div class="column contact">
|
||||||
|
@ -140,7 +140,7 @@ section {
|
||||||
.statistics {
|
.statistics {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, 150px);
|
grid-template-columns: repeat(auto-fit, 150px);
|
||||||
grid-template-rows: repeat(2, 1fr);
|
gap: 2rem 0;
|
||||||
p {
|
p {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
padding: 0 15px;
|
padding: 0 15px;
|
||||||
|
@ -157,6 +157,9 @@ section {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.contact {
|
.contact {
|
||||||
|
h4 {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
p {
|
p {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
|
@ -12,9 +12,14 @@ defmodule Mobilizon.GraphQL.Resolvers.Statistics do
|
||||||
{:ok,
|
{:ok,
|
||||||
%{
|
%{
|
||||||
number_of_users: StatisticsModule.get_cached_value(:local_users),
|
number_of_users: StatisticsModule.get_cached_value(:local_users),
|
||||||
number_of_events: StatisticsModule.get_cached_value(:local_events),
|
number_of_events: StatisticsModule.get_cached_value(:federation_events),
|
||||||
number_of_comments: StatisticsModule.get_cached_value(:local_comments),
|
number_of_local_events: StatisticsModule.get_cached_value(:local_events),
|
||||||
number_of_groups: StatisticsModule.get_cached_value(:local_groups)
|
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
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,9 +10,20 @@ defmodule Mobilizon.GraphQL.Schema.StatisticsType do
|
||||||
object :statistics do
|
object :statistics do
|
||||||
# Instance name
|
# Instance name
|
||||||
field(:number_of_users, :integer, description: "The number of local users")
|
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_events, :integer, description: "The total number of events")
|
||||||
field(:number_of_comments, :integer, description: "The number of local comments")
|
field(:number_of_local_events, :integer, description: "The number of local events")
|
||||||
field(:number_of_groups, :integer, description: "The number of local groups")
|
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
|
end
|
||||||
|
|
||||||
object :statistics_queries do
|
object :statistics_queries do
|
||||||
|
|
|
@ -1076,6 +1076,17 @@ defmodule Mobilizon.Actors do
|
||||||
|> Page.build_page(page, limit)
|
|> Page.build_page(page, limit)
|
||||||
end
|
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 """
|
@doc """
|
||||||
Returns the list of followings for an actor.
|
Returns the list of followings for an actor.
|
||||||
If actor A follows actor B and C, actor A's followings are B and C.
|
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()
|
|> Repo.all()
|
||||||
end
|
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 """
|
@doc """
|
||||||
Returns the list of external followings for an actor.
|
Returns the list of external followings for an actor.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -4,6 +4,7 @@ defmodule Mobilizon.Service.Statistics do
|
||||||
"""
|
"""
|
||||||
|
|
||||||
alias Mobilizon.{Actors, Discussions, Events, Users}
|
alias Mobilizon.{Actors, Discussions, Events, Users}
|
||||||
|
alias Mobilizon.Federation.ActivityPub.Relay
|
||||||
|
|
||||||
def get_cached_value(key) do
|
def get_cached_value(key) do
|
||||||
case Cachex.fetch(:statistics, key, fn key ->
|
case Cachex.fetch(:statistics, key, fn key ->
|
||||||
|
@ -44,4 +45,14 @@ defmodule Mobilizon.Service.Statistics do
|
||||||
defp create_cache(:federation_groups) do
|
defp create_cache(:federation_groups) do
|
||||||
Actors.count_groups()
|
Actors.count_groups()
|
||||||
end
|
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
|
end
|
||||||
|
|
46
test/graphql/resolvers/statistics_test.exs
Normal file
46
test/graphql/resolvers/statistics_test.exs
Normal file
|
@ -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
|
Loading…
Reference in a new issue