Show number of participants

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel 2019-09-11 16:37:30 +02:00
parent 6fe26fa68a
commit 44a8e2ecc7
8 changed files with 146 additions and 3 deletions

View File

@ -95,6 +95,10 @@ export const FETCH_EVENT = gql`
participants { participants {
${participantQuery} ${participantQuery}
}, },
participantStats {
approved,
unapproved
},
tags { tags {
${tagsQuery} ${tagsQuery}
}, },

View File

@ -92,6 +92,10 @@ export interface IEvent {
organizerActor?: IActor; organizerActor?: IActor;
attributedTo: IActor; attributedTo: IActor;
participantStats: {
approved: number;
unapproved: number;
};
participants: IParticipant[]; participants: IParticipant[];
relatedEvents: IEvent[]; relatedEvents: IEvent[];
@ -154,6 +158,7 @@ export class EventModel implements IEvent {
publishAt = new Date(); publishAt = new Date();
participantStats = { approved: 0, unapproved: 0};
participants: IParticipant[] = []; participants: IParticipant[] = [];
relatedEvents: IEvent[] = []; relatedEvents: IEvent[] = [];

View File

@ -18,6 +18,25 @@
</div> </div>
<h1 class="title">{{ event.title }}</h1> <h1 class="title">{{ event.title }}</h1>
</div> </div>
<span v-if="event.participantStats.approved > 0 && !actorIsParticipant()">
<translate
:translate-n="event.participantStats.approved"
:translate-params="{approved: event.participantStats.approved}"
translate-plural="%{ approved } persons are going">
One person is going
</translate>
</span>
<span v-else-if="event.participantStats.approved - 1 > 0 && actorIsParticipant()">
<translate
:translate-n="event.participantStats.approved - 1"
:translate-params="{approved: event.participantStats.approved - 1}"
translate-plural="You and %{ approved } persons are going">
You and one other person are going to this event
</translate>
</span>
<span v-else-if="actorIsParticipant()">
<translate>You're the only one going to this event</translate>
</span>
<div v-if="!actorIsOrganizer()" class="participate-button has-text-centered"> <div v-if="!actorIsOrganizer()" class="participate-button has-text-centered">
<a v-if="!actorIsParticipant()" @click="isJoinModalActive = true" class="button is-large is-primary is-rounded"> <a v-if="!actorIsParticipant()" @click="isJoinModalActive = true" class="button is-large is-primary is-rounded">
<b-icon icon="circle-outline"></b-icon> <b-icon icon="circle-outline"></b-icon>
@ -406,6 +425,7 @@ export default class Event extends Vue {
event.participants = event.participants event.participants = event.participants
.filter(p => p.actor.id !== data.leaveEvent.actor.id); .filter(p => p.actor.id !== data.leaveEvent.actor.id);
event.participantStats.approved = event.participantStats.approved - 1;
store.writeQuery({ query: FETCH_EVENT, data: { event } }); store.writeQuery({ query: FETCH_EVENT, data: { event } });
}, },

View File

@ -747,6 +747,28 @@ defmodule Mobilizon.Events do
|> paginate(page, limit) |> paginate(page, limit)
end end
def count_approved_participants(id) do
query =
from(
p in Participant,
where: p.role != ^:not_approved,
where: p.event_id == ^id
)
Repo.aggregate(query, :count, :id)
end
def count_unapproved_participants(id) do
query =
from(
p in Participant,
where: p.role == ^:not_approved,
where: p.event_id == ^id
)
Repo.aggregate(query, :count, :id)
end
@doc """ @doc """
Returns the list of participations for an actor. Returns the list of participations for an actor.

View File

@ -6,7 +6,7 @@ defmodule MobilizonWeb.Resolvers.Event do
alias Mobilizon.Addresses alias Mobilizon.Addresses
alias Mobilizon.Addresses.Address alias Mobilizon.Addresses.Address
alias Mobilizon.Events alias Mobilizon.Events
alias Mobilizon.Events.{Event, Participant} alias Mobilizon.Events.{Event, Participant, EventOptions}
alias Mobilizon.Media.Picture alias Mobilizon.Media.Picture
alias Mobilizon.Users.User alias Mobilizon.Users.User
alias Mobilizon.Actors alias Mobilizon.Actors
@ -51,6 +51,14 @@ defmodule MobilizonWeb.Resolvers.Event do
{:ok, Mobilizon.Events.list_participants_for_event(uuid, 1, 10)} {:ok, Mobilizon.Events.list_participants_for_event(uuid, 1, 10)}
end end
def stats_participants_for_event(%Event{id: id}, _args, _resolution) do
{:ok,
%{
approved: Mobilizon.Events.count_approved_participants(id),
unapproved: Mobilizon.Events.count_unapproved_participants(id)
}}
end
@doc """ @doc """
List related events List related events
""" """

View File

@ -54,6 +54,8 @@ defmodule MobilizonWeb.Schema.EventType do
field(:category, :string, description: "The event's category") field(:category, :string, description: "The event's category")
field(:participant_stats, :participant_stats, resolve: &Event.stats_participants_for_event/3)
field(:participants, list_of(:participant), field(:participants, list_of(:participant),
resolve: &Event.list_participants_for_event/3, resolve: &Event.list_participants_for_event/3,
description: "The event's participants" description: "The event's participants"
@ -92,6 +94,11 @@ defmodule MobilizonWeb.Schema.EventType do
value(:cancelled, description: "The event is cancelled") value(:cancelled, description: "The event is cancelled")
end end
object :participant_stats do
field(:approved, :integer, description: "The number of approved participants")
field(:unapproved, :integer, description: "The number of unapproved participants")
end
object :event_offer do object :event_offer do
field(:price, :float, description: "The price amount for this offer") field(:price, :float, description: "The price amount for this offer")
field(:price_currency, :string, description: "The currency for this price offer") field(:price_currency, :string, description: "The currency for this price offer")

View File

@ -1,5 +1,5 @@
# source: http://localhost:4000/api # source: http://localhost:4000/api
# timestamp: Mon Sep 09 2019 20:33:17 GMT+0200 (GMT+02:00) # timestamp: Wed Sep 11 2019 11:53:12 GMT+0200 (GMT+02:00)
schema { schema {
query: RootQueryType query: RootQueryType
@ -280,6 +280,7 @@ type Event implements ActionLogObject {
"""The event's organizer (as a person)""" """The event's organizer (as a person)"""
organizerActor: Actor organizerActor: Actor
participantStats: ParticipantStats
"""The event's participants""" """The event's participants"""
participants: [Participant] participants: [Participant]
@ -648,6 +649,14 @@ type Participant {
role: Int role: Int
} }
type ParticipantStats {
"""The number of approved participants"""
approved: Int
"""The number of unapproved participants"""
unapproved: Int
}
""" """
Represents a person identity Represents a person identity

View File

@ -12,7 +12,8 @@ defmodule MobilizonWeb.Resolvers.ParticipantResolverTest do
|> DateTime.truncate(:second), |> DateTime.truncate(:second),
uuid: "b5126423-f1af-43e4-a923-002a03003ba4", uuid: "b5126423-f1af-43e4-a923-002a03003ba4",
url: "some url", url: "some url",
category: "meeting" category: "meeting",
options: %{}
} }
setup %{conn: conn} do setup %{conn: conn} do
@ -387,5 +388,72 @@ defmodule MobilizonWeb.Resolvers.ParticipantResolverTest do
} }
] ]
end end
test "stats_participants_for_event/3 give the number of (un)approved participants", %{
conn: conn,
actor: actor
} do
event =
@event
|> Map.put(:organizer_actor_id, actor.id)
{:ok, event} = Events.create_event(event)
query = """
{
event(uuid: "#{event.uuid}") {
uuid,
participantStats {
approved,
unapproved
}
}
}
"""
res =
conn
|> get("/api", AbsintheHelpers.query_skeleton(query, "event"))
assert json_response(res, 200)["data"]["event"]["uuid"] == to_string(event.uuid)
assert json_response(res, 200)["data"]["event"]["participantStats"]["approved"] == 1
assert json_response(res, 200)["data"]["event"]["participantStats"]["unapproved"] == 0
moderator = insert(:actor)
Events.create_participant(%{
role: :moderator,
event_id: event.id,
actor_id: moderator.id
})
unapproved = insert(:actor)
Events.create_participant(%{
role: :not_approved,
event_id: event.id,
actor_id: unapproved.id
})
query = """
{
event(uuid: "#{event.uuid}") {
uuid,
participantStats {
approved,
unapproved
}
}
}
"""
res =
conn
|> get("/api", AbsintheHelpers.query_skeleton(query, "event"))
assert json_response(res, 200)["data"]["event"]["uuid"] == to_string(event.uuid)
assert json_response(res, 200)["data"]["event"]["participantStats"]["approved"] == 2
assert json_response(res, 200)["data"]["event"]["participantStats"]["unapproved"] == 1
end
end end
end end