Merge branch 'develop' into activation-meta
[akkoma] / lib / pleroma / notification.ex
index 5c8994e358e3f4ef9069982aaef8d51f7a4ff619..2ef1a80c5746a27013282f63cc91f39eb3724c2b 100644 (file)
@@ -31,7 +31,7 @@ defmodule Pleroma.Notification do
   schema "notifications" do
     field(:seen, :boolean, default: false)
     # This is an enum type in the database. If you add a new notification type,
-    # remembert to add a migration to add it to the `notifications_type` enum
+    # remember to add a migration to add it to the `notifications_type` enum
     # as well.
     field(:type, :string)
     belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
@@ -40,26 +40,6 @@ defmodule Pleroma.Notification do
     timestamps()
   end
 
-  def fill_in_notification_types do
-    query =
-      from(n in __MODULE__,
-        where: is_nil(n.type),
-        preload: :activity
-      )
-
-    query
-    |> Repo.all()
-    |> Enum.each(fn notification ->
-      type =
-        notification.activity
-        |> type_from_activity(no_cachex: true)
-
-      notification
-      |> changeset(%{type: type})
-      |> Repo.update()
-    end)
-  end
-
   def update_notification_type(user, activity) do
     with %__MODULE__{} = notification <-
            Repo.get_by(__MODULE__, user_id: user.id, activity_id: activity.id) do
@@ -81,9 +61,21 @@ defmodule Pleroma.Notification do
     |> Repo.aggregate(:count, :id)
   end
 
+  @notification_types ~w{
+    favourite
+    follow
+    follow_request
+    mention
+    move
+    pleroma:chat_mention
+    pleroma:emoji_reaction
+    reblog
+  }
+
   def changeset(%Notification{} = notification, attrs) do
     notification
     |> cast(attrs, [:seen, :type])
+    |> validate_inclusion(:type, @notification_types)
   end
 
   @spec last_read_query(User.t()) :: Ecto.Queryable.t()
@@ -174,8 +166,16 @@ defmodule Pleroma.Notification do
       query
       |> join(:left, [n, a], mutated_activity in Pleroma.Activity,
         on:
-          fragment("?->>'context'", a.data) ==
-            fragment("?->>'context'", mutated_activity.data) and
+          fragment(
+            "COALESCE((?->'object')->>'id', ?->>'object')",
+            a.data,
+            a.data
+          ) ==
+            fragment(
+              "COALESCE((?->'object')->>'id', ?->>'object')",
+              mutated_activity.data,
+              mutated_activity.data
+            ) and
             fragment("(?->>'type' = 'Like' or ?->>'type' = 'Announce')", a.data, a.data) and
             fragment("?->>'type'", mutated_activity.data) == "Create",
         as: :mutated_activity
@@ -367,27 +367,15 @@ defmodule Pleroma.Notification do
         do_send = do_send && user in enabled_receivers
         create_notification(activity, user, do_send)
       end)
+      |> Enum.reject(&is_nil/1)
 
     {:ok, notifications}
   end
 
-  defp type_from_activity(%{data: %{"type" => type}} = activity, opts \\ []) do
+  defp type_from_activity(%{data: %{"type" => type}} = activity) do
     case type do
       "Follow" ->
-        accepted_function =
-          if Keyword.get(opts, :no_cachex, false) do
-            # A special function to make this usable in a migration.
-            fn activity ->
-              with %User{} = follower <- User.get_by_ap_id(activity.data["actor"]),
-                   %User{} = followed <- User.get_by_ap_id(activity.data["object"]) do
-                Pleroma.FollowingRelationship.following?(follower, followed)
-              end
-            end
-          else
-            &Activity.follow_accepted?/1
-          end
-
-        if accepted_function.(activity) do
+        if Activity.follow_accepted?(activity) do
           "follow"
         else
           "follow_request"
@@ -562,6 +550,7 @@ defmodule Pleroma.Notification do
   def skip?(%Activity{} = activity, %User{} = user) do
     [
       :self,
+      :invisible,
       :followers,
       :follows,
       :non_followers,
@@ -578,6 +567,12 @@ defmodule Pleroma.Notification do
     activity.data["actor"] == user.ap_id
   end
 
+  def skip?(:invisible, %Activity{} = activity, _) do
+    actor = activity.data["actor"]
+    user = User.get_cached_by_ap_id(actor)
+    User.invisible?(user)
+  end
+
   def skip?(
         :followers,
         %Activity{} = activity,