Improve event creation form by introducting EventOptions
It's a subentity that holds additional metadata in a map database type Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -54,6 +54,7 @@ defmodule Mobilizon.Events.Event do
|
||||
field(:online_address, :string)
|
||||
field(:phone_address, :string)
|
||||
field(:category, :string)
|
||||
embeds_one(:options, Mobilizon.Events.EventOptions)
|
||||
belongs_to(:organizer_actor, Actor, foreign_key: :organizer_actor_id)
|
||||
belongs_to(:attributed_to, Actor, foreign_key: :attributed_to_id)
|
||||
many_to_many(:tags, Tag, join_through: "events_tags")
|
||||
@@ -87,6 +88,7 @@ defmodule Mobilizon.Events.Event do
|
||||
:picture_id,
|
||||
:physical_address_id
|
||||
])
|
||||
|> cast_embed(:options)
|
||||
|> validate_required([
|
||||
:title,
|
||||
:begins_on,
|
||||
|
||||
69
lib/mobilizon/events/event_options.ex
Normal file
69
lib/mobilizon/events/event_options.ex
Normal file
@@ -0,0 +1,69 @@
|
||||
import EctoEnum
|
||||
|
||||
defenum(Mobilizon.Events.CommentModeration, :comment_moderation, [:allow_all, :moderated, :closed])
|
||||
|
||||
defmodule Mobilizon.Events.EventOffer do
|
||||
@moduledoc """
|
||||
Represents an event offer
|
||||
"""
|
||||
use Ecto.Schema
|
||||
|
||||
embedded_schema do
|
||||
field(:price, :float)
|
||||
field(:price_currency, :string)
|
||||
field(:url, :string)
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Mobilizon.Events.EventParticipationCondition do
|
||||
@moduledoc """
|
||||
Represents an event participation condition
|
||||
"""
|
||||
use Ecto.Schema
|
||||
|
||||
embedded_schema do
|
||||
field(:title, :string)
|
||||
field(:content, :string)
|
||||
field(:url, :string)
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Mobilizon.Events.EventOptions do
|
||||
@moduledoc """
|
||||
Represents an event options
|
||||
"""
|
||||
use Ecto.Schema
|
||||
|
||||
alias Mobilizon.Events.{
|
||||
EventOptions,
|
||||
EventOffer,
|
||||
EventParticipationCondition,
|
||||
CommentModeration
|
||||
}
|
||||
|
||||
@primary_key false
|
||||
embedded_schema do
|
||||
field(:maximum_attendee_capacity, :integer)
|
||||
field(:remaining_attendee_capacity, :integer)
|
||||
field(:show_remaining_attendee_capacity, :boolean)
|
||||
embeds_many(:offers, EventOffer)
|
||||
embeds_many(:participation_condition, EventParticipationCondition)
|
||||
field(:attendees, {:array, :string})
|
||||
field(:program, :string)
|
||||
field(:comment_moderation, CommentModeration)
|
||||
field(:show_participation_price, :boolean)
|
||||
end
|
||||
|
||||
def changeset(%EventOptions{} = event_options, attrs) do
|
||||
event_options
|
||||
|> Ecto.Changeset.cast(attrs, [
|
||||
:maximum_attendee_capacity,
|
||||
:remaining_attendee_capacity,
|
||||
:show_remaining_attendee_capacity,
|
||||
:attendees,
|
||||
:program,
|
||||
:comment_moderation,
|
||||
:show_participation_price
|
||||
])
|
||||
end
|
||||
end
|
||||
@@ -14,14 +14,15 @@ defmodule MobilizonWeb.API.Events do
|
||||
@spec create_event(map()) :: {:ok, Activity.t(), Event.t()} | any()
|
||||
def create_event(
|
||||
%{
|
||||
title: title,
|
||||
description: description,
|
||||
organizer_actor_id: organizer_actor_id,
|
||||
begins_on: begins_on,
|
||||
category: category,
|
||||
tags: tags
|
||||
description: description,
|
||||
options: options,
|
||||
organizer_actor_id: organizer_actor_id,
|
||||
tags: tags,
|
||||
title: title
|
||||
} = args
|
||||
) do
|
||||
)
|
||||
when is_map(options) do
|
||||
with %Actor{url: url} = actor <-
|
||||
Actors.get_local_actor_with_everything(organizer_actor_id),
|
||||
physical_address <- Map.get(args, :physical_address, nil),
|
||||
@@ -38,7 +39,12 @@ defmodule MobilizonWeb.API.Events do
|
||||
content_html,
|
||||
picture,
|
||||
tags,
|
||||
%{begins_on: begins_on, physical_address: physical_address, category: category}
|
||||
%{
|
||||
begins_on: begins_on,
|
||||
physical_address: physical_address,
|
||||
category: Map.get(args, :category),
|
||||
options: options
|
||||
}
|
||||
) do
|
||||
ActivityPub.create(%{
|
||||
to: ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
|
||||
@@ -68,6 +68,7 @@ defmodule MobilizonWeb.Schema.EventType do
|
||||
|
||||
field(:updated_at, :datetime, description: "When the event was last updated")
|
||||
field(:created_at, :datetime, description: "When the event was created")
|
||||
field(:options, :event_options, description: "The event options")
|
||||
end
|
||||
|
||||
@desc "The list of visibility options for an event"
|
||||
@@ -90,6 +91,101 @@ defmodule MobilizonWeb.Schema.EventType do
|
||||
value(:cancelled, description: "The event is cancelled")
|
||||
end
|
||||
|
||||
object :event_offer do
|
||||
field(:price, :float, description: "The price amount for this offer")
|
||||
field(:price_currency, :string, description: "The currency for this price offer")
|
||||
field(:url, :string, description: "The URL to access to this offer")
|
||||
end
|
||||
|
||||
object :event_participation_condition do
|
||||
field(:title, :string, description: "The title for this condition")
|
||||
field(:content, :string, description: "The content for this condition")
|
||||
field(:url, :string, description: "The URL to access this condition")
|
||||
end
|
||||
|
||||
input_object :event_offer_input do
|
||||
field(:price, :float, description: "The price amount for this offer")
|
||||
field(:price_currency, :string, description: "The currency for this price offer")
|
||||
field(:url, :string, description: "The URL to access to this offer")
|
||||
end
|
||||
|
||||
input_object :event_participation_condition_input do
|
||||
field(:title, :string, description: "The title for this condition")
|
||||
field(:content, :string, description: "The content for this condition")
|
||||
field(:url, :string, description: "The URL to access this condition")
|
||||
end
|
||||
|
||||
@desc "The list of possible options for the event's status"
|
||||
enum :event_comment_moderation do
|
||||
value(:allow_all, description: "Anyone can comment under the event")
|
||||
value(:moderated, description: "Every comment has to be moderated by the admin")
|
||||
value(:closed, description: "No one can comment except for the admin")
|
||||
end
|
||||
|
||||
object :event_options do
|
||||
field(:maximum_attendee_capacity, :integer,
|
||||
description: "The maximum attendee capacity for this event"
|
||||
)
|
||||
|
||||
field(:remaining_attendee_capacity, :integer,
|
||||
description: "The number of remaining seats for this event"
|
||||
)
|
||||
|
||||
field(:show_remaining_attendee_capacity, :boolean,
|
||||
description: "Whether or not to show the number of remaining seats for this event"
|
||||
)
|
||||
|
||||
field(:offers, list_of(:event_offer), description: "The list of offers to show for this event")
|
||||
|
||||
field(:participation_conditions, list_of(:event_participation_condition),
|
||||
description: "The list of participation conditions to accept to join this event"
|
||||
)
|
||||
|
||||
field(:attendees, list_of(:string), description: "The list of special attendees")
|
||||
field(:program, :string, description: "The list of the event")
|
||||
|
||||
field(:comment_moderation, :event_comment_moderation,
|
||||
description: "The policy on public comment moderation under the event"
|
||||
)
|
||||
|
||||
field(:show_participation_price, :boolean,
|
||||
description: "Whether or not to show the participation price"
|
||||
)
|
||||
end
|
||||
|
||||
input_object :event_options_input do
|
||||
field(:maximum_attendee_capacity, :integer,
|
||||
description: "The maximum attendee capacity for this event"
|
||||
)
|
||||
|
||||
field(:remaining_attendee_capacity, :integer,
|
||||
description: "The number of remaining seats for this event"
|
||||
)
|
||||
|
||||
field(:show_remaining_attendee_capacity, :boolean,
|
||||
description: "Whether or not to show the number of remaining seats for this event"
|
||||
)
|
||||
|
||||
field(:offers, list_of(:event_offer_input),
|
||||
description: "The list of offers to show for this event"
|
||||
)
|
||||
|
||||
field(:participation_conditions, list_of(:event_participation_condition_input),
|
||||
description: "The list of participation conditions to accept to join this event"
|
||||
)
|
||||
|
||||
field(:attendees, list_of(:string), description: "The list of special attendees")
|
||||
field(:program, :string, description: "The list of the event")
|
||||
|
||||
field(:comment_moderation, :event_comment_moderation,
|
||||
description: "The policy on public comment moderation under the event"
|
||||
)
|
||||
|
||||
field(:show_participation_price, :boolean,
|
||||
description: "Whether or not to show the participation price"
|
||||
)
|
||||
end
|
||||
|
||||
object :event_queries do
|
||||
@desc "Get all events"
|
||||
field :events, list_of(:event) do
|
||||
@@ -131,8 +227,9 @@ defmodule MobilizonWeb.Schema.EventType do
|
||||
arg(:online_address, :string)
|
||||
arg(:phone_address, :string)
|
||||
arg(:organizer_actor_id, non_null(:id))
|
||||
arg(:category, :string)
|
||||
arg(:category, :string, default_value: "meeting")
|
||||
arg(:physical_address, :address_input)
|
||||
arg(:options, :event_options_input, default_value: %{})
|
||||
|
||||
resolve(&Event.create_event/3)
|
||||
end
|
||||
|
||||
@@ -34,7 +34,8 @@ defmodule Mobilizon.Service.ActivityPub.Converters.Event do
|
||||
{:actor, Actors.get_actor_by_url(object["actor"])},
|
||||
{:address, address_id} <-
|
||||
{:address, get_address(object["location"])},
|
||||
{:tags, tags} <- {:tags, fetch_tags(object["tag"])} do
|
||||
{:tags, tags} <- {:tags, fetch_tags(object["tag"])},
|
||||
{:options, options} <- {:options, get_options(object)} do
|
||||
picture_id =
|
||||
with true <- Map.has_key?(object, "attachment") && length(object["attachment"]) > 0,
|
||||
%Picture{id: picture_id} <-
|
||||
@@ -50,25 +51,41 @@ defmodule Mobilizon.Service.ActivityPub.Converters.Event do
|
||||
_ -> nil
|
||||
end
|
||||
|
||||
{:ok,
|
||||
%{
|
||||
"title" => object["name"],
|
||||
"description" => object["content"],
|
||||
"organizer_actor_id" => actor_id,
|
||||
"picture_id" => picture_id,
|
||||
"begins_on" => object["startTime"],
|
||||
"category" => object["category"],
|
||||
"url" => object["id"],
|
||||
"uuid" => object["uuid"],
|
||||
"tags" => tags,
|
||||
"physical_address_id" => address_id
|
||||
}}
|
||||
entity = %{
|
||||
"title" => object["name"],
|
||||
"description" => object["content"],
|
||||
"organizer_actor_id" => actor_id,
|
||||
"picture_id" => picture_id,
|
||||
"begins_on" => object["startTime"],
|
||||
"category" => object["category"],
|
||||
"url" => object["id"],
|
||||
"uuid" => object["uuid"],
|
||||
"tags" => tags,
|
||||
"physical_address_id" => address_id
|
||||
}
|
||||
|
||||
{:ok, Map.put(entity, "options", options)}
|
||||
else
|
||||
err ->
|
||||
{:error, err}
|
||||
end
|
||||
end
|
||||
|
||||
# Get only elements that we have in EventOptions
|
||||
defp get_options(object) do
|
||||
keys =
|
||||
Mobilizon.Events.EventOptions
|
||||
|> struct
|
||||
|> Map.keys()
|
||||
|> List.delete(:__struct__)
|
||||
|> Enum.map(&Utils.camelize/1)
|
||||
|
||||
Enum.reduce(object, %{}, fn {key, value}, acc ->
|
||||
(value && key in keys && Map.put(acc, Utils.underscore(key), value)) ||
|
||||
acc
|
||||
end)
|
||||
end
|
||||
|
||||
defp get_address(address_url) when is_bitstring(address_url) do
|
||||
get_address(%{"id" => address_url})
|
||||
end
|
||||
|
||||
@@ -298,7 +298,19 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
|
||||
do: res,
|
||||
else: Map.put(res, "location", make_address_data(metadata.physical_address))
|
||||
|
||||
if is_nil(picture), do: res, else: Map.put(res, "attachment", [make_picture_data(picture)])
|
||||
res =
|
||||
if is_nil(picture), do: res, else: Map.put(res, "attachment", [make_picture_data(picture)])
|
||||
|
||||
if is_nil(metadata.options) do
|
||||
res
|
||||
else
|
||||
options = struct(Mobilizon.Events.EventOptions, metadata.options) |> Map.from_struct()
|
||||
|
||||
Enum.reduce(options, res, fn {key, value}, acc ->
|
||||
(value && Map.put(acc, camelize(key), value)) ||
|
||||
acc
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
def make_address_data(%Address{} = address) do
|
||||
@@ -669,4 +681,21 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
|
||||
public_key = :public_key.pem_entry_encode(:RSAPublicKey, public_key)
|
||||
:public_key.pem_encode([public_key])
|
||||
end
|
||||
|
||||
def camelize(word) when is_atom(word) do
|
||||
camelize(to_string(word))
|
||||
end
|
||||
|
||||
def camelize(word) when is_bitstring(word) do
|
||||
{first, rest} = String.split_at(Macro.camelize(word), 1)
|
||||
String.downcase(first) <> rest
|
||||
end
|
||||
|
||||
def underscore(word) when is_atom(word) do
|
||||
underscore(to_string(word))
|
||||
end
|
||||
|
||||
def underscore(word) when is_bitstring(word) do
|
||||
Macro.underscore(word)
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user