Merge remote-tracking branch 'origin/develop' into features/mastoapi/2.6.0-conversations
[akkoma] / lib / pleroma / notification.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Notification do
6 use Ecto.Schema
7
8 alias Pleroma.Activity
9 alias Pleroma.Notification
10 alias Pleroma.Object
11 alias Pleroma.Pagination
12 alias Pleroma.Repo
13 alias Pleroma.User
14 alias Pleroma.Web.CommonAPI
15 alias Pleroma.Web.CommonAPI.Utils
16
17 import Ecto.Query
18 import Ecto.Changeset
19
20 schema "notifications" do
21 field(:seen, :boolean, default: false)
22 belongs_to(:user, User, type: Pleroma.FlakeId)
23 belongs_to(:activity, Activity, type: Pleroma.FlakeId)
24
25 timestamps()
26 end
27
28 def changeset(%Notification{} = notification, attrs) do
29 notification
30 |> cast(attrs, [:seen])
31 end
32
33 def for_user_query(user) do
34 Notification
35 |> where(user_id: ^user.id)
36 |> join(:inner, [n], activity in assoc(n, :activity))
37 |> join(:left, [n, a], object in Object,
38 on:
39 fragment(
40 "(?->>'id') = COALESCE((? -> 'object'::text) ->> 'id'::text)",
41 object.data,
42 a.data
43 )
44 )
45 |> preload([n, a, o], activity: {a, object: o})
46 end
47
48 def for_user(user, opts \\ %{}) do
49 user
50 |> for_user_query()
51 |> Pagination.fetch_paginated(opts)
52 end
53
54 def set_read_up_to(%{id: user_id} = _user, id) do
55 query =
56 from(
57 n in Notification,
58 where: n.user_id == ^user_id,
59 where: n.id <= ^id,
60 update: [
61 set: [seen: true]
62 ]
63 )
64
65 Repo.update_all(query, [])
66 end
67
68 def read_one(%User{} = user, notification_id) do
69 with {:ok, %Notification{} = notification} <- get(user, notification_id) do
70 notification
71 |> changeset(%{seen: true})
72 |> Repo.update()
73 end
74 end
75
76 def get(%{id: user_id} = _user, id) do
77 query =
78 from(
79 n in Notification,
80 where: n.id == ^id,
81 join: activity in assoc(n, :activity),
82 preload: [activity: activity]
83 )
84
85 notification = Repo.one(query)
86
87 case notification do
88 %{user_id: ^user_id} ->
89 {:ok, notification}
90
91 _ ->
92 {:error, "Cannot get notification"}
93 end
94 end
95
96 def clear(user) do
97 from(n in Notification, where: n.user_id == ^user.id)
98 |> Repo.delete_all()
99 end
100
101 def dismiss(%{id: user_id} = _user, id) do
102 notification = Repo.get(Notification, id)
103
104 case notification do
105 %{user_id: ^user_id} ->
106 Repo.delete(notification)
107
108 _ ->
109 {:error, "Cannot dismiss notification"}
110 end
111 end
112
113 def create_notifications(%Activity{data: %{"to" => _, "type" => type}} = activity)
114 when type in ["Create", "Like", "Announce", "Follow"] do
115 users = get_notified_from_activity(activity)
116
117 notifications = Enum.map(users, fn user -> create_notification(activity, user) end)
118 {:ok, notifications}
119 end
120
121 def create_notifications(_), do: {:ok, []}
122
123 # TODO move to sql, too.
124 def create_notification(%Activity{} = activity, %User{} = user) do
125 unless User.blocks?(user, %{ap_id: activity.data["actor"]}) or
126 CommonAPI.thread_muted?(user, activity) or user.ap_id == activity.data["actor"] or
127 (activity.data["type"] == "Follow" and
128 Enum.any?(Notification.for_user(user), fn notif ->
129 notif.activity.data["type"] == "Follow" and
130 notif.activity.data["actor"] == activity.data["actor"]
131 end)) do
132 notification = %Notification{user_id: user.id, activity: activity}
133 {:ok, notification} = Repo.insert(notification)
134 Pleroma.Web.Streamer.stream("user", notification)
135 Pleroma.Web.Push.send(notification)
136 notification
137 end
138 end
139
140 def get_notified_from_activity(activity, local_only \\ true)
141
142 def get_notified_from_activity(
143 %Activity{data: %{"to" => _, "type" => type} = _data} = activity,
144 local_only
145 )
146 when type in ["Create", "Like", "Announce", "Follow"] do
147 recipients =
148 []
149 |> Utils.maybe_notify_to_recipients(activity)
150 |> Utils.maybe_notify_mentioned_recipients(activity)
151 |> Enum.uniq()
152
153 User.get_users_from_set(recipients, local_only)
154 end
155
156 def get_notified_from_activity(_, _local_only), do: []
157 end