2018-10-11 17:37:39 +02:00
|
|
|
defmodule Mobilizon.Events.Participant do
|
2018-01-14 17:56:50 +01:00
|
|
|
@moduledoc """
|
2019-09-13 01:01:17 +02:00
|
|
|
Represents a participant, an actor participating to an event.
|
2018-01-14 17:56:50 +01:00
|
|
|
"""
|
2019-09-13 01:01:17 +02:00
|
|
|
|
2018-01-13 23:33:03 +01:00
|
|
|
use Ecto.Schema
|
2019-09-13 01:01:17 +02:00
|
|
|
|
2018-01-13 23:33:03 +01:00
|
|
|
import Ecto.Changeset
|
2019-09-13 01:01:17 +02:00
|
|
|
|
2018-10-11 17:37:39 +02:00
|
|
|
alias Mobilizon.Actors.Actor
|
2019-09-13 01:01:17 +02:00
|
|
|
alias Mobilizon.Events
|
2019-09-13 01:55:45 +02:00
|
|
|
alias Mobilizon.Events.{Event, ParticipantRole}
|
2021-09-10 11:27:59 +02:00
|
|
|
alias Mobilizon.Events.Participant.Metadata
|
2019-09-13 01:01:17 +02:00
|
|
|
|
2020-01-26 21:36:50 +01:00
|
|
|
alias Mobilizon.Web.Endpoint
|
2019-09-17 22:10:22 +02:00
|
|
|
|
2019-09-13 01:01:17 +02:00
|
|
|
@type t :: %__MODULE__{
|
2021-09-28 19:40:37 +02:00
|
|
|
id: String.t(),
|
2022-04-18 14:38:57 +02:00
|
|
|
role: atom(),
|
2021-10-13 12:57:35 +02:00
|
|
|
code: String.t(),
|
2019-09-13 01:01:17 +02:00
|
|
|
url: String.t(),
|
|
|
|
event: Event.t(),
|
2020-03-05 19:32:34 +01:00
|
|
|
actor: Actor.t(),
|
2020-07-09 17:24:28 +02:00
|
|
|
metadata: map()
|
2019-09-13 01:01:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@required_attrs [:url, :role, :event_id, :actor_id]
|
2021-10-13 12:57:35 +02:00
|
|
|
@optional_attrs [:code]
|
|
|
|
@attrs @required_attrs ++ @optional_attrs
|
2020-03-05 19:32:34 +01:00
|
|
|
|
|
|
|
@timestamps_opts [type: :utc_datetime]
|
2018-01-13 23:33:03 +01:00
|
|
|
|
2019-08-14 17:45:11 +02:00
|
|
|
@primary_key {:id, :binary_id, autogenerate: true}
|
2018-01-13 23:33:03 +01:00
|
|
|
schema "participants" do
|
2019-09-13 01:01:17 +02:00
|
|
|
field(:role, ParticipantRole, default: :participant)
|
2019-08-14 17:45:11 +02:00
|
|
|
field(:url, :string)
|
2021-10-13 12:57:35 +02:00
|
|
|
field(:code, :string)
|
2019-09-13 01:01:17 +02:00
|
|
|
|
2021-09-10 11:27:59 +02:00
|
|
|
embeds_one(:metadata, Metadata, on_replace: :delete)
|
2019-12-20 13:04:34 +01:00
|
|
|
|
2018-07-27 10:45:35 +02:00
|
|
|
belongs_to(:event, Event, primary_key: true)
|
|
|
|
belongs_to(:actor, Actor, primary_key: true)
|
2018-01-13 23:33:03 +01:00
|
|
|
|
|
|
|
timestamps()
|
|
|
|
end
|
|
|
|
|
2019-09-13 01:01:17 +02:00
|
|
|
@doc """
|
|
|
|
We check that the actor asking to leave the event is not it's only organizer.
|
|
|
|
We start by fetching the list of organizers and if there's only one of them
|
|
|
|
and that it's the actor requesting leaving the event we return true.
|
|
|
|
"""
|
|
|
|
@spec is_not_only_organizer(integer | String.t(), integer | String.t()) :: boolean
|
|
|
|
def is_not_only_organizer(event_id, actor_id) do
|
|
|
|
case Events.list_organizers_participants_for_event(event_id) do
|
2019-09-13 01:55:45 +02:00
|
|
|
[%__MODULE__{actor: %Actor{id: participant_actor_id}}] ->
|
2019-09-13 01:01:17 +02:00
|
|
|
participant_actor_id == actor_id
|
|
|
|
|
|
|
|
_ ->
|
|
|
|
false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-01-13 23:33:03 +01:00
|
|
|
@doc false
|
2021-09-24 16:46:42 +02:00
|
|
|
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
2019-09-13 01:55:45 +02:00
|
|
|
def changeset(%__MODULE__{} = participant, attrs) do
|
2018-01-13 23:33:03 +01:00
|
|
|
participant
|
2019-09-13 01:01:17 +02:00
|
|
|
|> cast(attrs, @attrs)
|
2021-09-10 11:27:59 +02:00
|
|
|
|> cast_embed(:metadata)
|
2019-09-13 01:01:17 +02:00
|
|
|
|> ensure_url()
|
2021-10-13 12:57:35 +02:00
|
|
|
|> add_code()
|
2019-09-13 01:01:17 +02:00
|
|
|
|> validate_required(@required_attrs)
|
2019-12-03 11:29:51 +01:00
|
|
|
|> unique_constraint(:actor_id, name: :participants_event_id_actor_id_index)
|
2019-08-14 17:45:11 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
# If there's a blank URL that's because we're doing the first insert
|
2019-09-13 01:01:17 +02:00
|
|
|
@spec ensure_url(Ecto.Changeset.t()) :: Ecto.Changeset.t()
|
2019-09-13 01:55:45 +02:00
|
|
|
defp ensure_url(%Ecto.Changeset{data: %__MODULE__{url: nil}} = changeset) do
|
2019-08-14 17:45:11 +02:00
|
|
|
case fetch_change(changeset, :url) do
|
2019-09-13 01:01:17 +02:00
|
|
|
{:ok, _url} ->
|
|
|
|
changeset
|
|
|
|
|
|
|
|
:error ->
|
|
|
|
update_url(changeset)
|
2019-08-14 17:45:11 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-09-13 01:01:17 +02:00
|
|
|
defp ensure_url(%Ecto.Changeset{} = changeset), do: changeset
|
2019-08-14 17:45:11 +02:00
|
|
|
|
2019-09-13 01:01:17 +02:00
|
|
|
defp update_url(%Ecto.Changeset{} = changeset) do
|
2019-08-14 17:45:11 +02:00
|
|
|
uuid = Ecto.UUID.generate()
|
2019-09-13 01:01:17 +02:00
|
|
|
url = generate_url(uuid)
|
2019-08-14 17:45:11 +02:00
|
|
|
|
|
|
|
changeset
|
2019-09-13 01:01:17 +02:00
|
|
|
|> put_change(:id, uuid)
|
|
|
|
|> put_change(:url, url)
|
2019-08-14 17:45:11 +02:00
|
|
|
end
|
|
|
|
|
2019-09-13 01:01:17 +02:00
|
|
|
@spec generate_url(String.t()) :: String.t()
|
2019-09-17 22:10:22 +02:00
|
|
|
defp generate_url(uuid), do: "#{Endpoint.url()}/join/event/#{uuid}"
|
2021-10-13 12:57:35 +02:00
|
|
|
|
|
|
|
@spec add_code(Ecto.Changeset.t()) :: Ecto.Changeset.t()
|
|
|
|
defp add_code(%Ecto.Changeset{} = changeset) do
|
|
|
|
case fetch_field(changeset, :code) do
|
|
|
|
{:data, nil} -> put_change(changeset, :code, generate_code())
|
|
|
|
{_, _code} -> changeset
|
|
|
|
:error -> put_change(changeset, :code, generate_code())
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# No lookalike symbols
|
2023-08-17 13:18:01 +02:00
|
|
|
@symbols ~c"6789BCDFGHJKLMNPQRTW"
|
2021-10-18 11:09:27 +02:00
|
|
|
@symbol_count Enum.count(@symbols) - 1
|
2021-10-13 12:57:35 +02:00
|
|
|
@code_length 6
|
|
|
|
|
|
|
|
@spec generate_code :: String.t()
|
|
|
|
defp generate_code do
|
|
|
|
for _ <- 1..@code_length,
|
|
|
|
into: "",
|
|
|
|
do: <<Enum.at(@symbols, :rand.uniform(@symbol_count))>>
|
|
|
|
end
|
2018-01-13 23:33:03 +01:00
|
|
|
end
|