Show number of participants
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
7bbed59f77
commit
c3b03a2e6b
|
@ -95,6 +95,10 @@ export const FETCH_EVENT = gql`
|
||||||
participants {
|
participants {
|
||||||
${participantQuery}
|
${participantQuery}
|
||||||
},
|
},
|
||||||
|
participantStats {
|
||||||
|
approved,
|
||||||
|
unapproved
|
||||||
|
},
|
||||||
tags {
|
tags {
|
||||||
${tagsQuery}
|
${tagsQuery}
|
||||||
},
|
},
|
||||||
|
|
|
@ -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[] = [];
|
||||||
|
|
|
@ -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 } });
|
||||||
},
|
},
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue