Add anonymous and remote participations
This commit is contained in:
@@ -4,22 +4,26 @@ defmodule Mobilizon.GraphQL.API.Participations do
|
||||
"""
|
||||
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Events
|
||||
alias Mobilizon.Events.{Event, Participant}
|
||||
|
||||
alias Mobilizon.Federation.ActivityPub
|
||||
|
||||
alias Mobilizon.Federation.ActivityPub.Activity
|
||||
alias Mobilizon.Web.Email.Participation
|
||||
|
||||
@spec join(Event.t(), Actor.t()) :: {:ok, Participant.t()}
|
||||
def join(%Event{id: event_id} = event, %Actor{id: actor_id} = actor) do
|
||||
with {:error, :participant_not_found} <- Mobilizon.Events.get_participant(event_id, actor_id),
|
||||
{:ok, activity, participant} <- ActivityPub.join(event, actor, true) do
|
||||
@spec join(Event.t(), Actor.t(), map()) :: {:ok, Activity.t(), Participant.t()}
|
||||
def join(%Event{id: event_id} = event, %Actor{id: actor_id} = actor, args \\ %{}) do
|
||||
with {:error, :participant_not_found} <-
|
||||
Mobilizon.Events.get_participant(event_id, actor_id, args),
|
||||
{:ok, activity, participant} <-
|
||||
ActivityPub.join(event, actor, Map.get(args, :local, true), %{metadata: args}) do
|
||||
{:ok, activity, participant}
|
||||
end
|
||||
end
|
||||
|
||||
def leave(%Event{} = event, %Actor{} = actor) do
|
||||
with {:ok, activity, participant} <- ActivityPub.leave(event, actor, true) do
|
||||
@spec leave(Event.t(), Actor.t()) :: {:ok, Activity.t(), Participant.t()}
|
||||
def leave(%Event{} = event, %Actor{} = actor, args \\ %{}) do
|
||||
with {:ok, activity, participant} <-
|
||||
ActivityPub.leave(event, actor, Map.get(args, :local, true), %{metadata: args}) do
|
||||
{:ok, activity, participant}
|
||||
end
|
||||
end
|
||||
@@ -27,14 +31,23 @@ defmodule Mobilizon.GraphQL.API.Participations do
|
||||
@doc """
|
||||
Update participation status
|
||||
"""
|
||||
def update(%Participant{} = participation, %Actor{} = moderator, :participant) do
|
||||
accept(participation, moderator)
|
||||
@spec update(Participant.t(), Actor.t(), atom()) :: {:ok, Activity.t(), Participant.t()}
|
||||
def update(%Participant{} = participation, %Actor{} = moderator, :participant),
|
||||
do: accept(participation, moderator)
|
||||
|
||||
@spec update(Participant.t(), Actor.t(), atom()) :: {:ok, Activity.t(), Participant.t()}
|
||||
def update(%Participant{} = participation, %Actor{} = _moderator, :not_approved) do
|
||||
with {:ok, %Participant{} = participant} <-
|
||||
Events.update_participant(participation, %{role: :not_approved}) do
|
||||
{:ok, nil, participant}
|
||||
end
|
||||
end
|
||||
|
||||
def update(%Participant{} = participation, %Actor{} = moderator, :rejected) do
|
||||
reject(participation, moderator)
|
||||
end
|
||||
@spec update(Participant.t(), Actor.t(), atom()) :: {:ok, Activity.t(), Participant.t()}
|
||||
def update(%Participant{} = participation, %Actor{} = moderator, :rejected),
|
||||
do: reject(participation, moderator)
|
||||
|
||||
@spec accept(Participant.t(), Actor.t()) :: {:ok, Activity.t(), Participant.t()}
|
||||
defp accept(
|
||||
%Participant{} = participation,
|
||||
%Actor{} = moderator
|
||||
@@ -51,6 +64,7 @@ defmodule Mobilizon.GraphQL.API.Participations do
|
||||
end
|
||||
end
|
||||
|
||||
@spec reject(Participant.t(), Actor.t()) :: {:ok, Activity.t(), Participant.t()}
|
||||
defp reject(
|
||||
%Participant{} = participation,
|
||||
%Actor{} = moderator
|
||||
|
||||
@@ -5,18 +5,18 @@ defmodule Mobilizon.GraphQL.Resolvers.Admin do
|
||||
|
||||
import Mobilizon.Users.Guards
|
||||
|
||||
alias Mobilizon.Actors
|
||||
alias Mobilizon.{Actors, Admin, Config, Events}
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Admin.ActionLog
|
||||
alias Mobilizon.Events
|
||||
alias Mobilizon.Admin.{ActionLog, Setting}
|
||||
alias Mobilizon.Config
|
||||
alias Mobilizon.Events.{Comment, Event}
|
||||
alias Mobilizon.Events.{Comment, Event}
|
||||
alias Mobilizon.Federation.ActivityPub.Relay
|
||||
alias Mobilizon.Reports.{Note, Report}
|
||||
alias Mobilizon.Service.Statistics
|
||||
alias Mobilizon.Storage.Page
|
||||
alias Mobilizon.Users.User
|
||||
|
||||
alias Mobilizon.Federation.ActivityPub.Relay
|
||||
|
||||
def list_action_logs(
|
||||
_parent,
|
||||
%{page: page, limit: limit},
|
||||
@@ -132,6 +132,43 @@ defmodule Mobilizon.GraphQL.Resolvers.Admin do
|
||||
{:error, "You need to be logged-in and an administrator to access dashboard statistics"}
|
||||
end
|
||||
|
||||
def get_settings(_parent, _args, %{
|
||||
context: %{current_user: %User{role: role}}
|
||||
})
|
||||
when is_admin(role) do
|
||||
{:ok,
|
||||
%{
|
||||
instance_description: Config.instance_description(),
|
||||
instance_name: Config.instance_name(),
|
||||
registrations_open: Config.instance_registrations_open?(),
|
||||
instance_terms: Config.instance_terms(),
|
||||
instance_terms_type: Config.instance_terms_type(),
|
||||
instance_terms_url: Config.instance_terms_url()
|
||||
}}
|
||||
end
|
||||
|
||||
def get_settings(_parent, _args, _resolution) do
|
||||
{:error, "You need to be logged-in and an administrator to access admin settings"}
|
||||
end
|
||||
|
||||
def save_settings(_parent, args, %{
|
||||
context: %{current_user: %User{role: role}}
|
||||
})
|
||||
when is_admin(role) do
|
||||
with {:ok, res} <- Admin.save_settings("instance", args) do
|
||||
res =
|
||||
res |> Enum.map(fn {key, %Setting{value: value}} -> {key, value} end) |> Enum.into(%{})
|
||||
|
||||
Config.clear_config_cache()
|
||||
|
||||
{:ok, res}
|
||||
end
|
||||
end
|
||||
|
||||
def save_settings(_parent, _args, _resolution) do
|
||||
{:error, "You need to be logged-in and an administrator to save admin settings"}
|
||||
end
|
||||
|
||||
def list_relay_followers(
|
||||
_parent,
|
||||
%{page: page, limit: limit},
|
||||
|
||||
@@ -25,25 +25,82 @@ defmodule Mobilizon.GraphQL.Resolvers.Config do
|
||||
_ -> nil
|
||||
end
|
||||
|
||||
{:ok,
|
||||
%{
|
||||
name: Config.instance_name(),
|
||||
registrations_open: Config.instance_registrations_open?(),
|
||||
registrations_whitelist: Config.instance_registrations_whitelist?(),
|
||||
demo_mode: Config.instance_demo_mode?(),
|
||||
description: Config.instance_description(),
|
||||
location: location,
|
||||
country_code: country_code,
|
||||
geocoding: %{
|
||||
provider: Config.instance_geocoding_provider(),
|
||||
autocomplete: Config.instance_geocoding_autocomplete()
|
||||
},
|
||||
maps: %{
|
||||
tiles: %{
|
||||
endpoint: Config.instance_maps_tiles_endpoint(),
|
||||
attribution: Config.instance_maps_tiles_attribution()
|
||||
}
|
||||
}
|
||||
}}
|
||||
data = Map.merge(config_cache(), %{location: location, country_code: country_code})
|
||||
|
||||
{:ok, data}
|
||||
end
|
||||
|
||||
def terms(_parent, %{locale: locale}, _resolution) do
|
||||
type = Config.instance_terms_type()
|
||||
|
||||
{url, body_html} =
|
||||
case type do
|
||||
"URL" -> {Config.instance_terms_url(), nil}
|
||||
"DEFAULT" -> {nil, Config.generate_terms(locale)}
|
||||
_ -> {nil, Config.instance_terms(locale)}
|
||||
end
|
||||
|
||||
{:ok, %{body_html: body_html, type: type, url: url}}
|
||||
end
|
||||
|
||||
defp config_cache do
|
||||
case Cachex.fetch(:config, "full_config", fn _key ->
|
||||
case build_config_cache() do
|
||||
value when not is_nil(value) -> {:commit, value}
|
||||
err -> {:ignore, err}
|
||||
end
|
||||
end) do
|
||||
{status, value} when status in [:ok, :commit] -> value
|
||||
_err -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defp build_config_cache do
|
||||
%{
|
||||
name: Config.instance_name(),
|
||||
registrations_open: Config.instance_registrations_open?(),
|
||||
registrations_whitelist: Config.instance_registrations_whitelist?(),
|
||||
demo_mode: Config.instance_demo_mode?(),
|
||||
description: Config.instance_description(),
|
||||
anonymous: %{
|
||||
participation: %{
|
||||
allowed: Config.anonymous_participation?(),
|
||||
validation: %{
|
||||
email: %{
|
||||
enabled: Config.anonymous_participation_email_required?(),
|
||||
confirmation_required:
|
||||
Config.anonymous_event_creation_email_confirmation_required?()
|
||||
},
|
||||
captcha: %{
|
||||
enabled: Config.anonymous_event_creation_email_captcha_required?()
|
||||
}
|
||||
}
|
||||
},
|
||||
event_creation: %{
|
||||
allowed: Config.anonymous_event_creation?(),
|
||||
validation: %{
|
||||
email: %{
|
||||
enabled: Config.anonymous_event_creation_email_required?(),
|
||||
confirmation_required:
|
||||
Config.anonymous_event_creation_email_confirmation_required?()
|
||||
},
|
||||
captcha: %{
|
||||
enabled: Config.anonymous_event_creation_email_captcha_required?()
|
||||
}
|
||||
}
|
||||
},
|
||||
actor_id: Config.anonymous_actor_id()
|
||||
},
|
||||
geocoding: %{
|
||||
provider: Config.instance_geocoding_provider(),
|
||||
autocomplete: Config.instance_geocoding_autocomplete()
|
||||
},
|
||||
maps: %{
|
||||
tiles: %{
|
||||
endpoint: Config.instance_maps_tiles_endpoint(),
|
||||
attribution: Config.instance_maps_tiles_attribution()
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,7 +5,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
|
||||
|
||||
alias Mobilizon.{Actors, Admin, Events}
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Events.{Event, EventParticipantStats, Participant}
|
||||
alias Mobilizon.Events.{Event, EventParticipantStats}
|
||||
alias Mobilizon.Users.User
|
||||
|
||||
alias Mobilizon.GraphQL.API
|
||||
@@ -19,7 +19,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
|
||||
|
||||
def list_events(_parent, %{page: page, limit: limit}, _resolution)
|
||||
when limit < @event_max_limit do
|
||||
{:ok, Mobilizon.Events.list_events(page, limit)}
|
||||
{:ok, Events.list_events(page, limit)}
|
||||
end
|
||||
|
||||
def list_events(_parent, %{page: _page, limit: _limit}, _resolution) do
|
||||
@@ -31,7 +31,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
|
||||
%{uuid: uuid},
|
||||
%{context: %{current_user: %User{id: user_id}}} = _resolution
|
||||
) do
|
||||
case {:has_event, Mobilizon.Events.get_own_event_by_uuid_with_preload(uuid, user_id)} do
|
||||
case {:has_event, Events.get_own_event_by_uuid_with_preload(uuid, user_id)} do
|
||||
{:has_event, %Event{} = event} ->
|
||||
{:ok, Map.put(event, :organizer_actor, Person.proxify_pictures(event.organizer_actor))}
|
||||
|
||||
@@ -45,7 +45,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
|
||||
end
|
||||
|
||||
def find_event(parent, %{uuid: uuid} = args, resolution) do
|
||||
case {:has_event, Mobilizon.Events.get_public_event_by_uuid_with_preload(uuid)} do
|
||||
case {:has_event, Events.get_public_event_by_uuid_with_preload(uuid)} do
|
||||
{:has_event, %Event{} = event} ->
|
||||
{:ok, Map.put(event, :organizer_actor, Person.proxify_pictures(event.organizer_actor))}
|
||||
|
||||
@@ -65,7 +65,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
|
||||
with {:is_owned, %Actor{} = _actor} <- User.owns_actor(user, actor_id),
|
||||
# Check that moderator has right
|
||||
{:actor_approve_permission, true} <-
|
||||
{:actor_approve_permission, Mobilizon.Events.moderator_for_event?(event_id, actor_id)} do
|
||||
{:actor_approve_permission, Events.moderator_for_event?(event_id, actor_id)} do
|
||||
roles =
|
||||
case roles do
|
||||
"" ->
|
||||
@@ -78,7 +78,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
|
||||
|> Enum.map(&String.to_existing_atom/1)
|
||||
end
|
||||
|
||||
{:ok, Mobilizon.Events.list_participants_for_event(event_id, roles, page, limit)}
|
||||
{:ok, Events.list_participants_for_event(event_id, roles, page, limit)}
|
||||
else
|
||||
{:is_owned, nil} ->
|
||||
{:error, "Moderator Actor ID is not owned by authenticated user"}
|
||||
@@ -142,118 +142,6 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
|
||||
|
||||
defp uniq_events(events), do: Enum.uniq_by(events, fn event -> event.uuid end)
|
||||
|
||||
@doc """
|
||||
Join an event for an actor
|
||||
"""
|
||||
def actor_join_event(
|
||||
_parent,
|
||||
%{actor_id: actor_id, event_id: event_id},
|
||||
%{context: %{current_user: user}}
|
||||
) do
|
||||
with {:is_owned, %Actor{} = actor} <- User.owns_actor(user, actor_id),
|
||||
{:has_event, {:ok, %Event{} = event}} <-
|
||||
{:has_event, Mobilizon.Events.get_event_with_preload(event_id)},
|
||||
{:error, :participant_not_found} <- Mobilizon.Events.get_participant(event_id, actor_id),
|
||||
{:ok, _activity, participant} <- API.Participations.join(event, actor),
|
||||
participant <-
|
||||
participant
|
||||
|> Map.put(:event, event)
|
||||
|> Map.put(:actor, Person.proxify_pictures(actor)) do
|
||||
{:ok, participant}
|
||||
else
|
||||
{:maximum_attendee_capacity, _} ->
|
||||
{:error, "The event has already reached its maximum capacity"}
|
||||
|
||||
{:has_event, _} ->
|
||||
{:error, "Event with this ID #{inspect(event_id)} doesn't exist"}
|
||||
|
||||
{:is_owned, nil} ->
|
||||
{:error, "Actor id is not owned by authenticated user"}
|
||||
|
||||
{:error, :event_not_found} ->
|
||||
{:error, "Event id not found"}
|
||||
|
||||
{:ok, %Participant{}} ->
|
||||
{:error, "You are already a participant of this event"}
|
||||
end
|
||||
end
|
||||
|
||||
def actor_join_event(_parent, _args, _resolution) do
|
||||
{:error, "You need to be logged-in to join an event"}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Leave an event for an actor
|
||||
"""
|
||||
def actor_leave_event(
|
||||
_parent,
|
||||
%{actor_id: actor_id, event_id: event_id},
|
||||
%{context: %{current_user: user}}
|
||||
) do
|
||||
with {:is_owned, %Actor{} = actor} <- User.owns_actor(user, actor_id),
|
||||
{:has_event, {:ok, %Event{} = event}} <-
|
||||
{:has_event, Mobilizon.Events.get_event_with_preload(event_id)},
|
||||
{:ok, _activity, _participant} <- API.Participations.leave(event, actor) do
|
||||
{:ok, %{event: %{id: event_id}, actor: %{id: actor_id}}}
|
||||
else
|
||||
{:has_event, _} ->
|
||||
{:error, "Event with this ID #{inspect(event_id)} doesn't exist"}
|
||||
|
||||
{:is_owned, nil} ->
|
||||
{:error, "Actor id is not owned by authenticated user"}
|
||||
|
||||
{:only_organizer, true} ->
|
||||
{:error, "You can't leave event because you're the only event creator participant"}
|
||||
|
||||
{:error, :participant_not_found} ->
|
||||
{:error, "Participant not found"}
|
||||
end
|
||||
end
|
||||
|
||||
def actor_leave_event(_parent, _args, _resolution) do
|
||||
{:error, "You need to be logged-in to leave an event"}
|
||||
end
|
||||
|
||||
def update_participation(
|
||||
_parent,
|
||||
%{id: participation_id, moderator_actor_id: moderator_actor_id, role: new_role},
|
||||
%{context: %{current_user: user}}
|
||||
) do
|
||||
# Check that moderator provided is rightly authenticated
|
||||
with {:is_owned, moderator_actor} <- User.owns_actor(user, moderator_actor_id),
|
||||
# Check that participation already exists
|
||||
{:has_participation, %Participant{role: old_role} = participation} <-
|
||||
{:has_participation, Mobilizon.Events.get_participant(participation_id)},
|
||||
{:same_role, false} <- {:same_role, new_role == old_role},
|
||||
# Check that moderator has right
|
||||
{:actor_approve_permission, true} <-
|
||||
{:actor_approve_permission,
|
||||
Mobilizon.Events.moderator_for_event?(participation.event.id, moderator_actor_id)},
|
||||
{:ok, _activity, participation} <-
|
||||
API.Participations.update(participation, moderator_actor, new_role) do
|
||||
{:ok, participation}
|
||||
else
|
||||
{:is_owned, nil} ->
|
||||
{:error, "Moderator Actor ID is not owned by authenticated user"}
|
||||
|
||||
{:has_participation, %Participant{role: role, id: id}} ->
|
||||
{:error,
|
||||
"Participant #{id} can't be approved since it's already a participant (with role #{role})"}
|
||||
|
||||
{:has_participation, nil} ->
|
||||
{:error, "Participant not found"}
|
||||
|
||||
{:actor_approve_permission, _} ->
|
||||
{:error, "Provided moderator actor ID doesn't have permission on this event"}
|
||||
|
||||
{:same_role, true} ->
|
||||
{:error, "Participant already has role #{new_role}"}
|
||||
|
||||
{:error, :participant_not_found} ->
|
||||
{:error, "Participant not found"}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Create an event
|
||||
"""
|
||||
|
||||
262
lib/graphql/resolvers/participant.ex
Normal file
262
lib/graphql/resolvers/participant.ex
Normal file
@@ -0,0 +1,262 @@
|
||||
defmodule Mobilizon.GraphQL.Resolvers.Participant do
|
||||
@moduledoc """
|
||||
Handles the participation-related GraphQL calls.
|
||||
"""
|
||||
alias Mobilizon.{Actors, Config, Crypto, Events}
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Events.{Event, Participant}
|
||||
alias Mobilizon.GraphQL.API.Participations
|
||||
alias Mobilizon.GraphQL.Resolvers.Person
|
||||
alias Mobilizon.Users.User
|
||||
alias Mobilizon.Web.Email
|
||||
alias Mobilizon.Web.Email.Checker
|
||||
require Logger
|
||||
|
||||
@doc """
|
||||
Join an event for an regular actor
|
||||
"""
|
||||
def actor_join_event(
|
||||
_parent,
|
||||
%{actor_id: actor_id, event_id: event_id},
|
||||
%{context: %{current_user: %User{} = user}}
|
||||
) do
|
||||
case User.owns_actor(user, actor_id) do
|
||||
{:is_owned, %Actor{} = actor} ->
|
||||
do_actor_join_event(actor, event_id)
|
||||
|
||||
_ ->
|
||||
{:error, "Actor id is not owned by authenticated user"}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Join an event for an anonymous actor
|
||||
"""
|
||||
def actor_join_event(
|
||||
_parent,
|
||||
%{actor_id: actor_id, event_id: event_id} = args,
|
||||
_resolution
|
||||
) do
|
||||
with {:has_event, {:ok, %Event{} = event}} <-
|
||||
{:has_event, Mobilizon.Events.get_event_with_preload(event_id)},
|
||||
{:anonymous_participation_enabled, true} <-
|
||||
{:anonymous_participation_enabled,
|
||||
event.local == true && Config.anonymous_participation?() &&
|
||||
event.options.anonymous_participation == true},
|
||||
{:anonymous_actor_id, true} <-
|
||||
{:anonymous_actor_id, to_string(Config.anonymous_actor_id()) == actor_id},
|
||||
{:email_required, true} <-
|
||||
{:email_required,
|
||||
Config.anonymous_participation_email_required?() &&
|
||||
args |> Map.get(:email) |> valid_email?()},
|
||||
{:confirmation_token, {confirmation_token, role}} <-
|
||||
{:confirmation_token,
|
||||
if(Config.anonymous_participation_email_confirmation_required?(),
|
||||
do: {Crypto.random_string(30), :not_confirmed},
|
||||
else: {nil, :participant}
|
||||
)},
|
||||
# We only federate if the participation is not to be confirmed later
|
||||
args <-
|
||||
args
|
||||
|> Map.put(:confirmation_token, confirmation_token)
|
||||
|> Map.put(:cancellation_token, Crypto.random_string(30))
|
||||
|> Map.put(:role, role)
|
||||
|> Map.put(:local, role == :participant),
|
||||
{:actor_not_found, %Actor{} = actor} <-
|
||||
{:actor_not_found, Actors.get_actor_with_preload(actor_id)},
|
||||
{:ok, %Participant{} = participant} <- do_actor_join_event(actor, event_id, args) do
|
||||
if Config.anonymous_participation_email_required?() &&
|
||||
Config.anonymous_participation_email_confirmation_required?() do
|
||||
args
|
||||
|> Map.get(:email)
|
||||
|> Email.Participation.anonymous_participation_confirmation(participant)
|
||||
|> Email.Mailer.deliver_later()
|
||||
end
|
||||
|
||||
{:ok, participant}
|
||||
else
|
||||
{:error, err} ->
|
||||
{:error, err}
|
||||
|
||||
{:has_event, _} ->
|
||||
{:error, "Event with this ID #{inspect(event_id)} doesn't exist"}
|
||||
|
||||
{:anonymous_participation_enabled, false} ->
|
||||
{:error, "Anonymous participation is not enabled"}
|
||||
|
||||
{:anonymous_actor_id, false} ->
|
||||
{:error, "Actor ID provided is not the anonymous actor one"}
|
||||
|
||||
{:email_required, _} ->
|
||||
{:error, "A valid email is required by your instance"}
|
||||
|
||||
{:actor_not_found, _} ->
|
||||
Logger.error(
|
||||
"The actor ID \"#{actor_id}\" provided by configuration doesn't match any actor in database"
|
||||
)
|
||||
|
||||
{:error, "Internal Error"}
|
||||
end
|
||||
end
|
||||
|
||||
def actor_join_event(_parent, _args, _resolution) do
|
||||
{:error, "You need to be logged-in to join an event"}
|
||||
end
|
||||
|
||||
@spec do_actor_join_event(Actor.t(), integer | String.t(), map()) ::
|
||||
{:ok, Participant.t()} | {:error, String.t()}
|
||||
defp do_actor_join_event(actor, event_id, args \\ %{}) do
|
||||
with {:has_event, {:ok, %Event{} = event}} <-
|
||||
{:has_event, Events.get_event_with_preload(event_id)},
|
||||
{:ok, _activity, participant} <- Participations.join(event, actor, args),
|
||||
%Participant{} = participant <-
|
||||
participant
|
||||
|> Map.put(:event, event)
|
||||
|> Map.put(:actor, Person.proxify_pictures(actor)) do
|
||||
{:ok, participant}
|
||||
else
|
||||
{:maximum_attendee_capacity, _} ->
|
||||
{:error, "The event has already reached its maximum capacity"}
|
||||
|
||||
{:has_event, _} ->
|
||||
{:error, "Event with this ID #{inspect(event_id)} doesn't exist"}
|
||||
|
||||
{:error, :event_not_found} ->
|
||||
{:error, "Event id not found"}
|
||||
|
||||
{:ok, %Participant{}} ->
|
||||
{:error, "You are already a participant of this event"}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Leave an event for an actor
|
||||
"""
|
||||
def actor_leave_event(
|
||||
_parent,
|
||||
%{actor_id: actor_id, event_id: event_id, token: token},
|
||||
_resolution
|
||||
) do
|
||||
with {:anonymous_participation_enabled, true} <-
|
||||
{:anonymous_participation_enabled, Config.anonymous_participation?()},
|
||||
{:anonymous_actor_id, true} <-
|
||||
{:anonymous_actor_id, to_string(Config.anonymous_actor_id()) == actor_id},
|
||||
{:has_event, {:ok, %Event{} = event}} <-
|
||||
{:has_event, Mobilizon.Events.get_event_with_preload(event_id)},
|
||||
%Actor{} = actor <- Actors.get_actor_with_preload(actor_id),
|
||||
{:ok, _activity, %Participant{id: participant_id} = _participant} <-
|
||||
Participations.leave(event, actor, %{local: false, cancellation_token: token}) do
|
||||
{:ok, %{event: %{id: event_id}, actor: %{id: actor_id}, id: participant_id}}
|
||||
else
|
||||
{:has_event, _} ->
|
||||
{:error, "Event with this ID #{inspect(event_id)} doesn't exist"}
|
||||
|
||||
{:is_owned, nil} ->
|
||||
{:error, "Actor id is not owned by authenticated user"}
|
||||
|
||||
{:only_organizer, true} ->
|
||||
{:error, "You can't leave event because you're the only event creator participant"}
|
||||
|
||||
{:error, :participant_not_found} ->
|
||||
{:error, "Participant not found"}
|
||||
end
|
||||
end
|
||||
|
||||
def actor_leave_event(
|
||||
_parent,
|
||||
%{actor_id: actor_id, event_id: event_id},
|
||||
%{context: %{current_user: user}}
|
||||
) do
|
||||
with {:is_owned, %Actor{} = actor} <- User.owns_actor(user, actor_id),
|
||||
{:has_event, {:ok, %Event{} = event}} <-
|
||||
{:has_event, Events.get_event_with_preload(event_id)},
|
||||
{:ok, _activity, _participant} <- Participations.leave(event, actor) do
|
||||
{:ok, %{event: %{id: event_id}, actor: %{id: actor_id}}}
|
||||
else
|
||||
{:has_event, _} ->
|
||||
{:error, "Event with this ID #{inspect(event_id)} doesn't exist"}
|
||||
|
||||
{:is_owned, nil} ->
|
||||
{:error, "Actor id is not owned by authenticated user"}
|
||||
|
||||
{:only_organizer, true} ->
|
||||
{:error, "You can't leave event because you're the only event creator participant"}
|
||||
|
||||
{:error, :participant_not_found} ->
|
||||
{:error, "Participant not found"}
|
||||
end
|
||||
end
|
||||
|
||||
def actor_leave_event(_parent, _args, _resolution) do
|
||||
{:error, "You need to be logged-in to leave an event"}
|
||||
end
|
||||
|
||||
def update_participation(
|
||||
_parent,
|
||||
%{id: participation_id, moderator_actor_id: moderator_actor_id, role: new_role},
|
||||
%{
|
||||
context: %{
|
||||
current_user: user
|
||||
}
|
||||
}
|
||||
) do
|
||||
# Check that moderator provided is rightly authenticated
|
||||
with {:is_owned, moderator_actor} <- User.owns_actor(user, moderator_actor_id),
|
||||
# Check that participation already exists
|
||||
{:has_participation, %Participant{role: old_role} = participation} <-
|
||||
{:has_participation, Events.get_participant(participation_id)},
|
||||
{:same_role, false} <- {:same_role, new_role == old_role},
|
||||
# Check that moderator has right
|
||||
{:actor_approve_permission, true} <-
|
||||
{:actor_approve_permission,
|
||||
Events.moderator_for_event?(participation.event.id, moderator_actor_id)},
|
||||
{:ok, _activity, participation} <-
|
||||
Participations.update(participation, moderator_actor, new_role) do
|
||||
{:ok, participation}
|
||||
else
|
||||
{:is_owned, nil} ->
|
||||
{:error, "Moderator Actor ID is not owned by authenticated user"}
|
||||
|
||||
{:has_participation, nil} ->
|
||||
{:error, "Participant not found"}
|
||||
|
||||
{:actor_approve_permission, _} ->
|
||||
{:error, "Provided moderator actor ID doesn't have permission on this event"}
|
||||
|
||||
{:same_role, true} ->
|
||||
{:error, "Participant already has role #{new_role}"}
|
||||
|
||||
{:error, :participant_not_found} ->
|
||||
{:error, "Participant not found"}
|
||||
end
|
||||
end
|
||||
|
||||
@spec confirm_participation_from_token(map(), map(), map()) ::
|
||||
{:ok, Participant.t()} | {:error, String.t()}
|
||||
def confirm_participation_from_token(
|
||||
_parent,
|
||||
%{confirmation_token: confirmation_token},
|
||||
_context
|
||||
) do
|
||||
with {:has_participant,
|
||||
%Participant{actor: actor, role: :not_confirmed, event: event} = participant} <-
|
||||
{:has_participant, Events.get_participant_by_confirmation_token(confirmation_token)},
|
||||
default_role <- Events.get_default_participant_role(event),
|
||||
{:ok, _activity, %Participant{} = participant} <-
|
||||
Participations.update(participant, actor, default_role) do
|
||||
{:ok, participant}
|
||||
else
|
||||
{:has_participant, _} ->
|
||||
{:error, "This token is invalid"}
|
||||
end
|
||||
end
|
||||
|
||||
@spec valid_email?(String.t() | nil) :: boolean
|
||||
defp valid_email?(email) when is_nil(email), do: false
|
||||
|
||||
defp valid_email?(email) when is_bitstring(email) do
|
||||
email
|
||||
|> String.trim()
|
||||
|> Checker.valid?()
|
||||
end
|
||||
end
|
||||
@@ -60,6 +60,21 @@ defmodule Mobilizon.GraphQL.Schema.AdminType do
|
||||
field(:number_of_reports, :integer, description: "The number of current opened reports")
|
||||
end
|
||||
|
||||
object :admin_settings do
|
||||
field(:instance_name, :string)
|
||||
field(:instance_description, :string)
|
||||
field(:instance_terms, :string)
|
||||
field(:instance_terms_type, :instance_terms_type)
|
||||
field(:instance_terms_url, :string)
|
||||
field(:registrations_open, :boolean)
|
||||
end
|
||||
|
||||
enum :instance_terms_type do
|
||||
value(:url, as: "URL")
|
||||
value(:default, as: "DEFAULT")
|
||||
value(:custom, as: "CUSTOM")
|
||||
end
|
||||
|
||||
object :admin_queries do
|
||||
@desc "Get the list of action logs"
|
||||
field :action_logs, type: list_of(:action_log) do
|
||||
@@ -72,6 +87,10 @@ defmodule Mobilizon.GraphQL.Schema.AdminType do
|
||||
resolve(&Admin.get_dashboard/3)
|
||||
end
|
||||
|
||||
field :admin_settings, type: :admin_settings do
|
||||
resolve(&Admin.get_settings/3)
|
||||
end
|
||||
|
||||
field :relay_followers, type: :paginated_follower_list do
|
||||
arg(:page, :integer, default_value: 1)
|
||||
arg(:limit, :integer, default_value: 10)
|
||||
@@ -115,5 +134,16 @@ defmodule Mobilizon.GraphQL.Schema.AdminType do
|
||||
|
||||
resolve(&Admin.reject_subscription/3)
|
||||
end
|
||||
|
||||
field :save_admin_settings, type: :admin_settings do
|
||||
arg(:instance_name, :string)
|
||||
arg(:instance_description, :string)
|
||||
arg(:instance_terms, :string)
|
||||
arg(:instance_terms_type, :instance_terms_type)
|
||||
arg(:instance_terms_url, :string)
|
||||
arg(:registrations_open, :boolean)
|
||||
|
||||
resolve(&Admin.save_settings/3)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,6 +19,18 @@ defmodule Mobilizon.GraphQL.Schema.ConfigType do
|
||||
field(:location, :lonlat)
|
||||
field(:geocoding, :geocoding)
|
||||
field(:maps, :maps)
|
||||
field(:anonymous, :anonymous)
|
||||
|
||||
field(:terms, :terms, description: "The instance's terms") do
|
||||
arg(:locale, :string, default_value: "en")
|
||||
resolve(&Config.terms/3)
|
||||
end
|
||||
end
|
||||
|
||||
object :terms do
|
||||
field(:url, :string)
|
||||
field(:type, :instance_terms_type)
|
||||
field(:body_html, :string)
|
||||
end
|
||||
|
||||
object :lonlat do
|
||||
@@ -41,6 +53,50 @@ defmodule Mobilizon.GraphQL.Schema.ConfigType do
|
||||
field(:attribution, :string)
|
||||
end
|
||||
|
||||
object :anonymous do
|
||||
field(:participation, :anonymous_participation)
|
||||
field(:event_creation, :anonymous_event_creation)
|
||||
field(:actor_id, :id)
|
||||
end
|
||||
|
||||
object :anonymous_participation do
|
||||
field(:allowed, :boolean)
|
||||
field(:validation, :anonymous_participation_validation)
|
||||
end
|
||||
|
||||
object :anonymous_participation_validation do
|
||||
field(:email, :anonymous_participation_validation_email)
|
||||
field(:captcha, :anonymous_participation_validation_captcha)
|
||||
end
|
||||
|
||||
object :anonymous_participation_validation_email do
|
||||
field(:enabled, :boolean)
|
||||
field(:confirmation_required, :boolean)
|
||||
end
|
||||
|
||||
object :anonymous_participation_validation_captcha do
|
||||
field(:enabled, :boolean)
|
||||
end
|
||||
|
||||
object :anonymous_event_creation do
|
||||
field(:allowed, :boolean)
|
||||
field(:validation, :anonymous_event_creation_validation)
|
||||
end
|
||||
|
||||
object :anonymous_event_creation_validation do
|
||||
field(:email, :anonymous_event_creation_validation_email)
|
||||
field(:captcha, :anonymous_event_creation_validation_captcha)
|
||||
end
|
||||
|
||||
object :anonymous_event_creation_validation_email do
|
||||
field(:enabled, :boolean)
|
||||
field(:confirmation_required, :boolean)
|
||||
end
|
||||
|
||||
object :anonymous_event_creation_validation_captcha do
|
||||
field(:enabled, :boolean)
|
||||
end
|
||||
|
||||
object :config_queries do
|
||||
@desc "Get the instance config"
|
||||
field :config, :config do
|
||||
|
||||
@@ -122,6 +122,7 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
|
||||
)
|
||||
|
||||
field(:not_approved, :integer, description: "The number of not approved participants")
|
||||
field(:not_confirmed, :integer, description: "The number of not confirmed participants")
|
||||
field(:rejected, :integer, description: "The number of rejected participants")
|
||||
|
||||
field(:participant, :integer,
|
||||
@@ -177,6 +178,10 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
|
||||
description: "Whether or not to show the number of remaining seats for this event"
|
||||
)
|
||||
|
||||
field(:anonymous_participation, :boolean,
|
||||
description: "Whether or not to allow anonymous participation (if the server allows it)"
|
||||
)
|
||||
|
||||
field(:offers, list_of(:event_offer), description: "The list of offers to show for this event")
|
||||
|
||||
field(:participation_conditions, list_of(:event_participation_condition),
|
||||
@@ -211,6 +216,11 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
|
||||
description: "Whether or not to show the number of remaining seats for this event"
|
||||
)
|
||||
|
||||
field(:anonymous_participation, :boolean,
|
||||
default_value: false,
|
||||
description: "Whether or not to allow anonymous participation (if the server allows it)"
|
||||
)
|
||||
|
||||
field(:offers, list_of(:event_offer_input),
|
||||
description: "The list of offers to show for this event"
|
||||
)
|
||||
|
||||
@@ -8,7 +8,7 @@ defmodule Mobilizon.GraphQL.Schema.Events.ParticipantType do
|
||||
import Absinthe.Resolution.Helpers, only: [dataloader: 1]
|
||||
|
||||
alias Mobilizon.{Actors, Events}
|
||||
alias Mobilizon.GraphQL.Resolvers.Event
|
||||
alias Mobilizon.GraphQL.Resolvers.Participant
|
||||
|
||||
@desc "Represents a participant to an event"
|
||||
object :participant do
|
||||
@@ -29,10 +29,21 @@ defmodule Mobilizon.GraphQL.Schema.Events.ParticipantType do
|
||||
)
|
||||
|
||||
field(:role, :participant_role_enum, description: "The role of this actor at this event")
|
||||
|
||||
field(:metadata, :participant_metadata,
|
||||
description: "The metadata associated to this participant"
|
||||
)
|
||||
end
|
||||
|
||||
object :participant_metadata do
|
||||
field(:cancellation_token, :string,
|
||||
description: "The eventual token to leave an event when user is anonymous"
|
||||
)
|
||||
end
|
||||
|
||||
enum :participant_role_enum do
|
||||
value(:not_approved)
|
||||
value(:not_confirmed)
|
||||
value(:participant)
|
||||
value(:moderator)
|
||||
value(:administrator)
|
||||
@@ -52,16 +63,18 @@ defmodule Mobilizon.GraphQL.Schema.Events.ParticipantType do
|
||||
field :join_event, :participant do
|
||||
arg(:event_id, non_null(:id))
|
||||
arg(:actor_id, non_null(:id))
|
||||
arg(:email, :string)
|
||||
|
||||
resolve(&Event.actor_join_event/3)
|
||||
resolve(&Participant.actor_join_event/3)
|
||||
end
|
||||
|
||||
@desc "Leave an event"
|
||||
field :leave_event, :deleted_participant do
|
||||
arg(:event_id, non_null(:id))
|
||||
arg(:actor_id, non_null(:id))
|
||||
arg(:token, :string)
|
||||
|
||||
resolve(&Event.actor_leave_event/3)
|
||||
resolve(&Participant.actor_leave_event/3)
|
||||
end
|
||||
|
||||
@desc "Accept a participation"
|
||||
@@ -70,7 +83,13 @@ defmodule Mobilizon.GraphQL.Schema.Events.ParticipantType do
|
||||
arg(:role, non_null(:participant_role_enum))
|
||||
arg(:moderator_actor_id, non_null(:id))
|
||||
|
||||
resolve(&Event.update_participation/3)
|
||||
resolve(&Participant.update_participation/3)
|
||||
end
|
||||
|
||||
@desc "Confirm a participation"
|
||||
field :confirm_participation, :participant do
|
||||
arg(:confirmation_token, non_null(:string))
|
||||
resolve(&Participant.confirm_participation_from_token/3)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user