defmodule Mobilizon.Service.Activity.Comment do @moduledoc """ Insert a comment activity """ alias Mobilizon.Actors.Actor alias Mobilizon.{Discussions, Events} alias Mobilizon.Discussions.Comment alias Mobilizon.Events.Event alias Mobilizon.Service.Activity alias Mobilizon.Service.Workers.{ActivityBuilder, LegacyNotifierBuilder} import Mobilizon.Service.Activity.Utils, only: [maybe_inserted_at: 0] @behaviour Activity @impl Activity def insert_activity(comment, options \\ []) def insert_activity( %Comment{ actor_id: actor_id, event_id: event_id } = comment, options ) when not is_nil(actor_id) and not is_nil(event_id) do with {:ok, %Event{} = event} <- Events.get_event_with_preload(event_id) do res = [] # Notify the actors mentionned |> handle_notification(:mentionned, comment, event, options) # Notify participants if there's a new announcement |> handle_notification(:announcement, comment, event, options) # Notify event organizer or group that there's new comments |> handle_notification(:organizer, comment, event, options) {:ok, res} end end def insert_activity(_, _), do: {:ok, nil} @impl Activity def get_object(comment_id) do Discussions.get_comment(comment_id) end @common_params %{ "type" => :comment, "object_type" => :comment } @spec handle_notification(Keyword.t(), notification_type, Comment.t(), Event.t(), Keyword.t()) :: Keyword.t() defp handle_notification(global_res, function, comment, event, options) do {:ok, res} = notify(function, comment, event, options) Keyword.put(global_res, function, res) end @spec legacy_notifier_enqueue(map()) :: :ok defp legacy_notifier_enqueue(args) do LegacyNotifierBuilder.enqueue( :legacy_notify, @common_params |> Map.merge(maybe_inserted_at()) |> Map.merge(args) ) end @type notification_type :: :mentionned | :announcement | :organizer # An actor is mentionned @spec notify(notification_type(), Comment.t(), Event.t(), Keyword.t()) :: {:ok, :enqueued} | {:ok, :skipped} defp notify( :mentionned, %Comment{actor_id: actor_id, id: comment_id, mentions: mentions}, %Event{ uuid: uuid, title: title }, _options ) when length(mentions) > 0 do legacy_notifier_enqueue(%{ "subject" => :event_comment_mention, "subject_params" => %{ event_uuid: uuid, event_title: title }, "author_id" => actor_id, "object_id" => to_string(comment_id), "mentions" => Enum.map(mentions, & &1.actor_id) }) {:ok, :enqueued} end # An event has a new announcement, send it to the participants defp notify( :announcement, %Comment{actor_id: actor_id, is_announcement: true, id: comment_id}, %Event{ id: event_id, uuid: uuid, title: title }, _options ) do legacy_notifier_enqueue(%{ "subject" => :participation_event_comment, "subject_params" => %{ event_id: event_id, event_uuid: uuid, event_title: title }, "author_id" => actor_id, "object_id" => to_string(comment_id) }) {:ok, :enqueued} end # A group event has a new comment, send it as an activity defp notify( :announcement, %Comment{ actor_id: actor_id, in_reply_to_comment_id: in_reply_to_comment_id, id: comment_id }, %Event{ uuid: uuid, title: title, attributed_to: %Actor{type: :Group, id: group_id} }, options ) do ActivityBuilder.enqueue(:build_activity, %{ "type" => "event", "subject" => Keyword.fetch!(options, :subject), "subject_params" => %{ event_title: title, event_uuid: uuid, comment_reply_to: !is_nil(in_reply_to_comment_id) }, "group_id" => group_id, "author_id" => actor_id, "object_type" => "comment", "object_id" => to_string(comment_id), "inserted_at" => DateTime.utc_now() }) {:ok, :enqueued} end # An event has a new comment, send it to the organizer defp notify( :organizer, %Comment{ actor_id: actor_id, in_reply_to_comment_id: in_reply_to_comment_id, id: comment_id, uuid: comment_uuid } = comment, %Event{ uuid: event_uuid, title: title, attributed_to: nil, organizer_actor_id: organizer_actor_id }, _options ) when actor_id !== organizer_actor_id do legacy_notifier_enqueue(%{ "subject" => :event_new_comment, "subject_params" => %{ event_title: title, event_uuid: event_uuid, comment_reply_to: !is_nil(in_reply_to_comment_id), comment_uuid: comment_uuid, comment_reply_to_uuid: reply_to_comment_uuid(comment) }, "author_id" => actor_id, "object_id" => to_string(comment_id) }) {:ok, :enqueued} end defp notify(_, _, _, _), do: {:ok, :skipped} @spec reply_to_comment_uuid(Comment.t()) :: String.t() | nil defp reply_to_comment_uuid(%Comment{in_reply_to_comment: %Comment{uuid: comment_reply_to_uuid}}), do: comment_reply_to_uuid defp reply_to_comment_uuid(%Comment{in_reply_to_comment: _}), do: nil end