Make sure people can't join an event with limited participants

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel 2019-10-11 11:50:06 +02:00
parent 872bcd6b29
commit 74fe9db43e
5 changed files with 101 additions and 3 deletions

View File

@ -762,6 +762,17 @@ defmodule Mobilizon.Events do
|> Repo.aggregate(:count, :id)
end
@doc """
Counts participant participants.
"""
@spec count_participant_participants(integer | String.t()) :: integer
def count_participant_participants(event_id) do
event_id
|> count_participants_query()
|> filter_participant_role()
|> Repo.aggregate(:count, :id)
end
@doc """
Counts unapproved participants.
"""
@ -1457,6 +1468,11 @@ defmodule Mobilizon.Events do
from(p in query, where: p.role not in ^[:not_approved, :rejected])
end
@spec filter_participant_role(Ecto.Query.t()) :: Ecto.Query.t()
defp filter_participant_role(query) do
from(p in query, where: p.role == ^:participant)
end
@spec filter_unapproved_role(Ecto.Query.t()) :: Ecto.Query.t()
defp filter_unapproved_role(query) do
from(p in query, where: p.role == ^:not_approved)

View File

@ -170,6 +170,9 @@ defmodule MobilizonWeb.Resolvers.Event do
|> Map.put(:actor, Person.proxify_pictures(actor)) do
{:ok, participant}
else
{:maximum_attendee_capacity, _} ->
{:error, "The event has already reached it's maximum capacity"}
{:has_event, _} ->
{:error, "Event with this ID #{inspect(event_id)} doesn't exist"}

View File

@ -411,8 +411,16 @@ defmodule Mobilizon.Service.ActivityPub do
def join(object, actor, local \\ true)
def join(%Event{} = event, %Actor{} = actor, local) do
with role <- Mobilizon.Events.get_default_participant_role(event),
def join(%Event{options: options} = event, %Actor{} = actor, local) do
# TODO Refactor me for federation
with maximum_attendee_capacity <-
Map.get(options, :maximum_attendee_capacity, 2_000_000) || false,
{:maximum_attendee_capacity, true} <-
{:maximum_attendee_capacity,
!maximum_attendee_capacity ||
Mobilizon.Events.count_participant_participants(event.id) <
maximum_attendee_capacity},
role <- Mobilizon.Events.get_default_participant_role(event),
{:ok, %Participant{} = participant} <-
Mobilizon.Events.create_participant(%{
role: role,

View File

@ -74,6 +74,76 @@ defmodule MobilizonWeb.Resolvers.ParticipantResolverTest do
assert hd(json_response(res, 200)["errors"])["message"] =~ "already a participant"
end
test "actor_join_event/3 doesn't work if the event already has too much participants", %{
conn: conn,
actor: actor
} do
event = insert(:event, options: %{maximum_attendee_capacity: 2})
insert(:participant, event: event, actor: actor, role: :creator)
insert(:participant, event: event, role: :participant)
insert(:participant, event: event, role: :not_approved)
insert(:participant, event: event, role: :rejected)
user_participant = insert(:user)
actor_participant = insert(:actor, user: user_participant)
mutation = """
mutation {
joinEvent(
actor_id: #{actor_participant.id},
event_id: #{event.id}
) {
role,
actor {
id
},
event {
id
}
}
}
"""
res =
conn
|> auth_conn(user_participant)
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
assert json_response(res, 200)["errors"] == nil
assert json_response(res, 200)["data"]["joinEvent"]["role"] == "PARTICIPANT"
assert json_response(res, 200)["data"]["joinEvent"]["event"]["id"] == to_string(event.id)
assert json_response(res, 200)["data"]["joinEvent"]["actor"]["id"] ==
to_string(actor_participant.id)
user_participant_2 = insert(:user)
actor_participant_2 = insert(:actor, user: user_participant_2)
mutation = """
mutation {
joinEvent(
actor_id: #{actor_participant_2.id},
event_id: #{event.id}
) {
role,
actor {
id
},
event {
id
}
}
}
"""
res =
conn
|> auth_conn(user_participant_2)
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
assert hd(json_response(res, 200)["errors"])["message"] ==
"The event has already reached it's maximum capacity"
end
test "actor_join_event/3 should check the actor is owned by the user", %{
conn: conn,
user: user

View File

@ -124,7 +124,8 @@ defmodule Mobilizon.Factory do
url: Routes.page_url(Endpoint, :event, uuid),
picture: insert(:picture),
uuid: uuid,
join_options: :free
join_options: :free,
options: %{}
}
end