@ -7,6 +7,7 @@ defmodule Mobilizon.Events do
import Ecto.Query
import EctoEnum
alias Ecto . { Multi , Changeset }
import Mobilizon.Storage.Ecto
@ -17,6 +18,7 @@ defmodule Mobilizon.Events do
alias Mobilizon.Events . {
Comment ,
Event ,
EventParticipantStats ,
FeedToken ,
Participant ,
Session ,
@ -82,6 +84,8 @@ defmodule Mobilizon.Events do
@event_preloads [
:organizer_actor ,
:attributed_to ,
:mentions ,
:sessions ,
:tracks ,
:tags ,
@ -90,7 +94,7 @@ defmodule Mobilizon.Events do
:picture
]
@comment_preloads [ :actor , :attributed_to , :in_reply_to_comment ]
@comment_preloads [ :actor , :attributed_to , :in_reply_to_comment , :tags , :mentions ]
@doc """
Gets a single event .
@ -235,81 +239,103 @@ defmodule Mobilizon.Events do
|> Repo . one ( )
end
def get_or_create_event ( %{ " url " = > url } = attrs ) do
case Repo . get_by ( Event , url : url ) do
% Event { } = event -> { :ok , Repo . preload ( event , @event_preloads ) }
nil -> create_event ( attrs )
end
end
@doc """
Creates an event .
"""
@spec create_event ( map ) :: { :ok , Event . t ( ) } | { :error , Ecto.Changeset . t ( ) }
@spec create_event ( map ) :: { :ok , Event . t ( ) } | { :error , Changeset. t ( ) }
def create_event ( attrs \\ %{ } ) do
with { :ok , % Event { draft : false } = event } <- do_create_event ( attrs ) ,
{ :ok , % Participant { } = _participant } <-
create_participant ( %{
actor_id : event . organizer_actor_id ,
role : :creator ,
event_id : event . id
} ) do
with { :ok , %{ insert : % Event { } = event } } <- do_create_event ( attrs ) ,
% Event { } = event <- Repo . preload ( event , @event_preloads ) do
Task . start ( fn -> Search . insert_search_event ( event ) end )
{ :ok , event }
else
# We don't create a creator participant if the event is a draft
{ :ok , % Event { draft : true } = event } -> { :ok , event }
err -> err
end
end
@spec do_create_event ( map ) :: { :ok , Event . t ( ) } | { :error , Ecto.Changeset . t ( ) }
# We start by inserting the event and then insert a first participant if the event is not a draft
@spec do_create_event ( map ) :: { :ok , Event . t ( ) } | { :error , Changeset . t ( ) }
defp do_create_event ( attrs ) do
with { :ok , % Event { } = event } <-
% Event { }
|> Event . changeset ( attrs )
|> Ecto.Changeset . put_assoc ( :tags , Map . get ( attrs , " tags " , [ ] ) )
|> Repo . insert ( ) ,
% Event { } = event <-
Repo . preload ( event , [ :tags , :organizer_actor , :physical_address , :picture ] ) do
{ :ok , event }
end
Multi . new ( )
|> Multi . insert ( :insert , Event . changeset ( % Event { } , attrs ) )
|> Multi . run ( :write , fn _repo , %{ insert : % Event { draft : draft } = event } ->
with { :is_draft , false } <- { :is_draft , draft } ,
{ :ok , % Participant { } = participant } <-
create_participant (
%{
event_id : event . id ,
role : :creator ,
actor_id : event . organizer_actor_id
} ,
false
) do
{ :ok , participant }
else
{ :is_draft , true } -> { :ok , nil }
err -> err
end
end )
|> Repo . transaction ( )
end
@doc """
Updates an event .
"""
@spec update_event ( Event . t ( ) , map ) :: { :ok , Event . t ( ) } | { :error , Ecto.Changeset . t ( ) }
def update_event (
% Event { draft : old_draft_status , id : event_id , organizer_actor_id : organizer_actor_id } =
old_event ,
attrs
) do
with % Ecto.Changeset { changes : changes } = changeset <-
old_event |> Repo . preload ( :tags ) |> Event . update_changeset ( attrs ) do
with { :ok , % Event { draft : new_draft_status } = new_event } <- Repo . update ( changeset ) do
# If the event is no longer a draft
if old_draft_status == true && new_draft_status == false do
{ :ok , % Participant { } = _participant } =
create_participant ( %{
event_id : event_id ,
role : :creator ,
actor_id : organizer_actor_id
} )
end
Cachex . del ( :ics , " event_ #{ new_event . uuid } " )
Mobilizon.Service.Events.Tool . calculate_event_diff_and_send_notifications (
old_event ,
new_event ,
changes
)
Task . start ( fn -> Search . update_search_event ( new_event ) end )
We start by updating the event and then insert a first participant if the event is not a draft anymore
"""
@spec update_event ( Event . t ( ) , map ) :: { :ok , Event . t ( ) } | { :error , Changeset . t ( ) }
def update_event ( % Event { } = old_event , attrs ) do
with % Changeset { changes : changes } = changeset <-
Event . update_changeset ( Repo . preload ( old_event , :tags ) , attrs ) ,
{ :ok , %{ update : % Event { } = new_event } } <-
Multi . new ( )
|> Multi . update (
:update ,
changeset
)
|> Multi . run ( :write , fn _repo , %{ update : % Event { draft : draft } = event } ->
with { :is_draft , false } <- { :is_draft , draft } ,
{ :ok , % Participant { } = participant } <-
create_participant (
%{
event_id : event . id ,
role : :creator ,
actor_id : event . organizer_actor_id
} ,
false
) do
{ :ok , participant }
else
{ :is_draft , true } -> { :ok , nil }
err -> err
end
end )
|> Repo . transaction ( ) do
Cachex . del ( :ics , " event_ #{ new_event . uuid } " )
Mobilizon.Service.Events.Tool . calculate_event_diff_and_send_notifications (
old_event ,
new_event ,
changes
)
{ :ok , new_event }
end
Task . start ( fn -> Search . update_search_event ( new_event ) end )
{ :ok , Repo . preload ( new_event , @event_preloads ) }
end
end
@doc """
Deletes an event .
"""
@spec delete_event ( Event . t ( ) ) :: { :ok , Event . t ( ) } | { :error , Ecto.Changeset . t ( ) }
@spec delete_event ( Event . t ( ) ) :: { :ok , Event . t ( ) } | { :error , Changeset. t ( ) }
def delete_event ( % Event { } = event ) , do : Repo . delete ( event )
@doc """
@ -450,7 +476,7 @@ defmodule Mobilizon.Events do
@doc """
Gets an existing tag or creates the new one .
"""
@spec get_or_create_tag ( map ) :: { :ok , Tag . t ( ) } | { :error , Ecto. Changeset. t ( ) }
@spec get_or_create_tag ( map ) :: { :ok , Tag . t ( ) } | { :error , Changeset. t ( ) }
def get_or_create_tag ( %{ " name " = > " # " <> title } ) do
case Repo . get_by ( Tag , title : title ) do
% Tag { } = tag ->
@ -461,10 +487,24 @@ defmodule Mobilizon.Events do
end
end
@doc """
Gets an existing tag or creates the new one .
"""
@spec get_or_create_tag ( String . t ( ) ) :: { :ok , Tag . t ( ) } | { :error , Changeset . t ( ) }
def get_or_create_tag ( title ) do
case Repo . get_by ( Tag , title : title ) do
% Tag { } = tag ->
{ :ok , tag }
nil ->
create_tag ( %{ " title " = > title } )
end
end
@doc """
Creates a tag .
"""
@spec create_tag ( map ) :: { :ok , Tag . t ( ) } | { :error , Ecto.Changeset . t ( ) }
@spec create_tag ( map ) :: { :ok , Tag . t ( ) } | { :error , Changeset. t ( ) }
def create_tag ( attrs \\ %{ } ) do
% Tag { }
|> Tag . changeset ( attrs )
@ -474,7 +514,7 @@ defmodule Mobilizon.Events do
@doc """
Updates a tag .
"""
@spec update_tag ( Tag . t ( ) , map ) :: { :ok , Tag . t ( ) } | { :error , Ecto. Changeset. t ( ) }
@spec update_tag ( Tag . t ( ) , map ) :: { :ok , Tag . t ( ) } | { :error , Changeset. t ( ) }
def update_tag ( % Tag { } = tag , attrs ) do
tag
|> Tag . changeset ( attrs )
@ -484,7 +524,7 @@ defmodule Mobilizon.Events do
@doc """
Deletes a tag .
"""
@spec delete_tag ( Tag . t ( ) ) :: { :ok , Tag . t ( ) } | { :error , Ecto. Changeset. t ( ) }
@spec delete_tag ( Tag . t ( ) ) :: { :ok , Tag . t ( ) } | { :error , Changeset. t ( ) }
def delete_tag ( % Tag { } = tag ) , do : Repo . delete ( tag )
@doc """
@ -524,7 +564,7 @@ defmodule Mobilizon.Events do
@doc """
Creates a relation between two tags .
"""
@spec create_tag_relation ( map ) :: { :ok , TagRelation . t ( ) } | { :error , Ecto. Changeset. t ( ) }
@spec create_tag_relation ( map ) :: { :ok , TagRelation . t ( ) } | { :error , Changeset. t ( ) }
def create_tag_relation ( attrs \\ { } ) do
% TagRelation { }
|> TagRelation . changeset ( attrs )
@ -538,7 +578,7 @@ defmodule Mobilizon.Events do
Removes a tag relation .
"""
@spec delete_tag_relation ( TagRelation . t ( ) ) ::
{ :ok , TagRelation . t ( ) } | { :error , Ecto. Changeset. t ( ) }
{ :ok , TagRelation . t ( ) } | { :error , Changeset. t ( ) }
def delete_tag_relation ( % TagRelation { } = tag_relation ) do
Repo . delete ( tag_relation )
end
@ -763,7 +803,7 @@ defmodule Mobilizon.Events do
end
@doc """
Counts participant participants .
Counts participant participants ( participants with no extra role )
"""
@spec count_participant_participants ( integer | String . t ( ) ) :: integer
def count_participant_participants ( event_id ) do
@ -773,17 +813,6 @@ defmodule Mobilizon.Events do
|> Repo . aggregate ( :count , :id )
end
@doc """
Counts unapproved participants .
"""
@spec count_unapproved_participants ( integer | String . t ( ) ) :: integer
def count_unapproved_participants ( event_id ) do
event_id
|> count_participants_query ( )
|> filter_unapproved_role ( )
|> Repo . aggregate ( :count , :id )
end
@doc """
Counts rejected participants .
"""
@ -805,12 +834,40 @@ defmodule Mobilizon.Events do
@doc """
Creates a participant .
"""
@spec create_participant ( map ) :: { :ok , Participant . t ( ) } | { :error , Ecto.Changeset . t ( ) }
def create_participant ( attrs \\ %{ } ) do
with { :ok , % Participant { } = participant } <-
% Participant { }
|> Participant . changeset ( attrs )
|> Repo . insert ( ) do
@spec create_participant ( map ) :: { :ok , Participant . t ( ) } | { :error , Changeset . t ( ) }
def create_participant ( attrs \\ %{ } , update_event_participation_stats \\ true ) do
with { :ok , %{ participant : % Participant { } = participant } } <-
Multi . new ( )
|> Multi . insert ( :participant , Participant . changeset ( % Participant { } , attrs ) )
|> Multi . run ( :update_event_participation_stats , fn _repo ,
%{
participant :
% Participant {
role : role ,
event_id : event_id
} = _participant
} ->
with { :update_event_participation_stats , true } <-
{ :update_event_participation_stats , update_event_participation_stats } ,
{ :ok , % Event { } = event } <- get_event ( event_id ) ,
% EventParticipantStats { } = participant_stats <-
Map . get ( event , :participant_stats ) ,
% EventParticipantStats { } = participant_stats <-
Map . update ( participant_stats , role , 0 , & ( &1 + 1 ) ) ,
{ :ok , % Event { } = event } <-
event
|> Event . update_changeset ( %{
participant_stats : Map . from_struct ( participant_stats )
} )
|> Repo . update ( ) do
{ :ok , event }
else
{ :update_event_participation_stats , false } -> { :ok , nil }
{ :error , :event_not_found } -> { :error , :event_not_found }
err -> { :error , err }
end
end )
|> Repo . transaction ( ) do
{ :ok , Repo . preload ( participant , [ :event , :actor ] ) }
end
end
@ -819,7 +876,7 @@ defmodule Mobilizon.Events do
Updates a participant .
"""
@spec update_participant ( Participant . t ( ) , map ) ::
{ :ok , Participant . t ( ) } | { :error , Ecto. Changeset. t ( ) }
{ :ok , Participant . t ( ) } | { :error , Changeset. t ( ) }
def update_participant ( % Participant { } = participant , attrs ) do
participant
|> Participant . changeset ( attrs )
@ -830,7 +887,7 @@ defmodule Mobilizon.Events do
Deletes a participant .
"""
@spec delete_participant ( Participant . t ( ) ) ::
{ :ok , Participant . t ( ) } | { :error , Ecto. Changeset. t ( ) }
{ :ok , Participant . t ( ) } | { :error , Changeset. t ( ) }
def delete_participant ( % Participant { } = participant ) , do : Repo . delete ( participant )
@doc """
@ -843,7 +900,7 @@ defmodule Mobilizon.Events do
@doc """
Creates a session .
"""
@spec create_session ( map ) :: { :ok , Session . t ( ) } | { :error , Ecto. Changeset. t ( ) }
@spec create_session ( map ) :: { :ok , Session . t ( ) } | { :error , Changeset. t ( ) }
def create_session ( attrs \\ %{ } ) do
% Session { }
|> Session . changeset ( attrs )
@ -853,7 +910,7 @@ defmodule Mobilizon.Events do
@doc """
Updates a session .
"""
@spec update_session ( Session . t ( ) , map ) :: { :ok , Session . t ( ) } | { :error , Ecto. Changeset. t ( ) }
@spec update_session ( Session . t ( ) , map ) :: { :ok , Session . t ( ) } | { :error , Changeset. t ( ) }
def update_session ( % Session { } = session , attrs ) do
session
|> Session . changeset ( attrs )
@ -863,7 +920,7 @@ defmodule Mobilizon.Events do
@doc """
Deletes a session .
"""
@spec delete_session ( Session . t ( ) ) :: { :ok , Session . t ( ) } | { :error , Ecto. Changeset. t ( ) }
@spec delete_session ( Session . t ( ) ) :: { :ok , Session . t ( ) } | { :error , Changeset. t ( ) }
def delete_session ( % Session { } = session ) , do : Repo . delete ( session )
@doc """
@ -892,7 +949,7 @@ defmodule Mobilizon.Events do
@doc """
Creates a track .
"""