diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index ce8c470a57..7ce7975323 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -76,6 +76,7 @@ def unread_notifications_count(%User{id: user_id}) do status pleroma:participation_accepted pleroma:participation_request + pleroma:event_reminder } def changeset(%Notification{} = notification, attrs) do @@ -521,6 +522,28 @@ def create_poll_notifications(%Activity{} = activity) do end end + def create_event_notifications(%Activity{} = activity) do + with %Object{data: %{"type" => "Event", "actor" => actor} = data} <- + Object.normalize(activity) do + participations = + case data do + %{"participations" => participations} when is_list(participations) -> participations + _ -> [] + end + + notifications = + Enum.reduce([actor | participations], [], fn ap_id, acc -> + with %User{local: true} = user <- User.get_by_ap_id(ap_id) do + [create_notification(activity, user, type: "pleroma:event_reminder") | acc] + else + _ -> acc + end + end) + + {:ok, notifications} + end + end + @doc """ Returns a tuple with 2 elements: {notification-enabled receivers, currently disabled receivers (blocking / [thread] muting)} diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 317c23e219..d41a7b3a12 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -25,6 +25,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do alias Pleroma.Web.Streamer alias Pleroma.Web.WebFinger alias Pleroma.Workers.BackgroundWorker + alias Pleroma.Workers.EventReminderWorker alias Pleroma.Workers.PollWorker import Ecto.Changeset @@ -309,6 +310,7 @@ defp do_create(%{to: to, actor: actor, context: context, object: object} = param {:ok, _actor} <- update_last_status_at_if_public(actor, activity), _ <- notify_and_stream(activity), :ok <- maybe_schedule_poll_notifications(activity), + :ok <- maybe_schedule_event_notifications(activity), :ok <- maybe_federate(activity) do {:ok, activity} else @@ -328,6 +330,11 @@ defp maybe_schedule_poll_notifications(activity) do :ok end + defp maybe_schedule_event_notifications(activity) do + EventReminderWorker.schedule_event_reminder(activity) + :ok + end + @spec listen(map()) :: {:ok, Activity.t()} | {:error, any()} def listen(%{to: to, actor: actor, context: context, object: object} = params) do additional = params[:additional] || %{} diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index 1ae98dfec7..93d3afcf0f 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -23,6 +23,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.Push alias Pleroma.Web.Streamer + alias Pleroma.Workers.EventReminderWorker alias Pleroma.Workers.PollWorker require Logger @@ -516,6 +517,13 @@ def handle_object_creation(%{"type" => "Answer"} = object_map, _activity, meta) end end + def handle_object_creation(%{"type" => "Event"} = object, activity, meta) do + with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do + EventReminderWorker.schedule_event_reminder(activity) + {:ok, object, meta} + end + end + def handle_object_creation(%{"type" => objtype} = object, _activity, meta) when objtype in ~w[Audio Video Event Article Note Page] do with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do diff --git a/lib/pleroma/web/api_spec/operations/notification_operation.ex b/lib/pleroma/web/api_spec/operations/notification_operation.ex index cfef484379..ff7b083d3d 100644 --- a/lib/pleroma/web/api_spec/operations/notification_operation.ex +++ b/lib/pleroma/web/api_spec/operations/notification_operation.ex @@ -204,7 +204,8 @@ defp notification_type do "poll", "status", "pleroma:participation_accepted", - "pleroma:participation_request" + "pleroma:participation_request", + "pleroma:event_reminder" ], description: """ The type of event that resulted in the notification. @@ -220,6 +221,7 @@ defp notification_type do - `pleroma:chat_mention` - Someone mentioned you in a chat message - `pleroma:report` - Someone was reported - `status` - Someone you are subscribed to created a status + - `pleroma:event_reminder` – An event you are participating in or created is taking place soon - `pleroma:participation_request - Someone wants to participate in your event - `pleroma:participation_accepted - Your event participation request was accepted """ diff --git a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex index 0c3dbc9fc4..cf79046a06 100644 --- a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex @@ -54,6 +54,7 @@ def index(conn, %{account_id: account_id} = params) do status pleroma:participation_request pleroma:participation_accepted + pleroma:event_reminder } def index(%{assigns: %{user: user}} = conn, params) do params = diff --git a/lib/pleroma/web/mastodon_api/views/notification_view.ex b/lib/pleroma/web/mastodon_api/views/notification_view.ex index 0643946d8e..abf50363da 100644 --- a/lib/pleroma/web/mastodon_api/views/notification_view.ex +++ b/lib/pleroma/web/mastodon_api/views/notification_view.ex @@ -100,10 +100,7 @@ def render( } case notification.type do - "mention" -> - put_status(response, activity, reading_user, status_render_opts) - - "status" -> + type when type in ["mention", "status", "poll", "pleroma:event_reminder"] -> put_status(response, activity, reading_user, status_render_opts) "favourite" -> @@ -115,9 +112,6 @@ def render( "move" -> put_target(response, activity, reading_user, %{}) - "poll" -> - put_status(response, activity, reading_user, status_render_opts) - "pleroma:emoji_reaction" -> response |> put_status(parent_activity_fn.(), reading_user, status_render_opts) diff --git a/lib/pleroma/workers/event_reminder_worker.ex b/lib/pleroma/workers/event_reminder_worker.ex new file mode 100644 index 0000000000..20e33af1b4 --- /dev/null +++ b/lib/pleroma/workers/event_reminder_worker.ex @@ -0,0 +1,49 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.EventReminderWorker do + @moduledoc """ + Generates notifications for upcoming events. + """ + use Pleroma.Workers.WorkerHelper, queue: "event_notifications" + + alias Pleroma.Activity + alias Pleroma.Notification + alias Pleroma.Object + + @impl Oban.Worker + def perform(%Job{args: %{"op" => "event_reminder", "activity_id" => activity_id}}) do + with %Activity{} = activity <- find_event_activity(activity_id) do + Notification.create_event_notifications(activity) + end + end + + defp find_event_activity(activity_id) do + with nil <- Activity.get_by_id(activity_id) do + {:error, :event_activity_not_found} + end + end + + def schedule_event_reminder(%Activity{data: %{"type" => "Create"}, id: activity_id} = activity) do + with %Object{data: %{"type" => "Event", "startTime" => start_time}} <- + Object.normalize(activity), + {:ok, start_time} <- NaiveDateTime.from_iso8601(start_time), + :lt <- + NaiveDateTime.compare( + start_time |> NaiveDateTime.add(60 * 60 * -2, :second), + NaiveDateTime.utc_now() + ) do + %{ + op: "event_reminder", + activity_id: activity_id + } + |> new(scheduled_at: start_time |> NaiveDateTime.add(60 * 60 * -2, :second)) + |> Oban.insert() + else + _ -> {:error, activity} + end + end + + def schedule_event_reminder(activity), do: {:error, activity} +end diff --git a/priv/repo/migrations/20220819171321_add_pleroma_participation_accepted_to_notifications_enum.exs b/priv/repo/migrations/20220819171321_add_pleroma_participation_accepted_to_notifications_enum.exs index 2a2f271307..c23be2c5fd 100644 --- a/priv/repo/migrations/20220819171321_add_pleroma_participation_accepted_to_notifications_enum.exs +++ b/priv/repo/migrations/20220819171321_add_pleroma_participation_accepted_to_notifications_enum.exs @@ -13,6 +13,11 @@ def up do alter type notification_type add value 'pleroma:participation_request' """ |> execute() + + """ + alter type notification_type add value 'pleroma:event_reminder' + """ + |> execute() end def down do @@ -21,7 +26,7 @@ def down do end """ - delete from notifications where type in ('pleroma:participation_accepted', 'pleroma:participation_request') + delete from notifications where type in ('pleroma:participation_accepted', 'pleroma:participation_request', 'pleroma:event_reminder') """ |> execute()