mobilizon.chapril.org-mobil.../lib/mobilizon/events/participant.ex

108 lines
3.0 KiB
Elixir
Raw Normal View History

defmodule Mobilizon.Events.Participant do
@moduledoc """
2019-09-13 01:01:17 +02:00
Represents a participant, an actor participating to an event.
"""
2019-09-13 01:01:17 +02:00
use Ecto.Schema
2019-09-13 01:01:17 +02:00
import Ecto.Changeset
2019-09-13 01:01:17 +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}
alias Mobilizon.Web.Email.Checker
2019-09-13 01:01:17 +02:00
2020-01-26 21:36:50 +01:00
alias Mobilizon.Web.Endpoint
2019-09-13 01:01:17 +02:00
@type t :: %__MODULE__{
role: ParticipantRole.t(),
url: String.t(),
event: Event.t(),
actor: Actor.t(),
metadata: Map.t()
2019-09-13 01:01:17 +02:00
}
@required_attrs [:url, :role, :event_id, :actor_id]
@attrs @required_attrs
@metadata_attrs [:email, :confirmation_token, :cancellation_token, :message]
@timestamps_opts [type: :utc_datetime]
@primary_key {:id, :binary_id, autogenerate: true}
schema "participants" do
2019-09-13 01:01:17 +02:00
field(:role, ParticipantRole, default: :participant)
field(:url, :string)
2019-09-13 01:01:17 +02:00
embeds_one :metadata, Metadata, on_replace: :delete do
field(:email, :string)
field(:confirmation_token, :string)
field(:cancellation_token, :string)
field(:message, :string)
end
belongs_to(:event, Event, primary_key: true)
belongs_to(:actor, Actor, primary_key: true)
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
@doc false
2019-09-13 01:01:17 +02:00
@spec changeset(t, map) :: Ecto.Changeset.t()
2019-09-13 01:55:45 +02:00
def changeset(%__MODULE__{} = participant, attrs) do
participant
2019-09-13 01:01:17 +02:00
|> cast(attrs, @attrs)
|> cast_embed(:metadata, with: &metadata_changeset/2)
2019-09-13 01:01:17 +02:00
|> ensure_url()
|> validate_required(@required_attrs)
|> unique_constraint(:actor_id, name: :participants_event_id_actor_id_index)
end
defp metadata_changeset(schema, params) do
schema
|> cast(params, @metadata_attrs)
|> Checker.validate_changeset()
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
case fetch_change(changeset, :url) do
2019-09-13 01:01:17 +02:00
{:ok, _url} ->
changeset
:error ->
update_url(changeset)
end
end
2019-09-13 01:01:17 +02:00
defp ensure_url(%Ecto.Changeset{} = changeset), do: changeset
2019-09-13 01:01:17 +02:00
defp update_url(%Ecto.Changeset{} = changeset) do
uuid = Ecto.UUID.generate()
2019-09-13 01:01:17 +02:00
url = generate_url(uuid)
changeset
2019-09-13 01:01:17 +02:00
|> put_change(:id, uuid)
|> put_change(:url, url)
end
2019-09-13 01:01:17 +02:00
@spec generate_url(String.t()) :: String.t()
defp generate_url(uuid), do: "#{Endpoint.url()}/join/event/#{uuid}"
end