Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into remake-remodel-dms
[akkoma] / lib / pleroma / web / activity_pub / side_effects.ex
1 defmodule Pleroma.Web.ActivityPub.SideEffects do
2 @moduledoc """
3 This module looks at an inserted object and executes the side effects that it
4 implies. For example, a `Like` activity will increase the like count on the
5 liked object, a `Follow` activity will add the user to the follower
6 collection, and so on.
7 """
8 alias Pleroma.Activity
9 alias Pleroma.Chat
10 alias Pleroma.Notification
11 alias Pleroma.Object
12 alias Pleroma.Repo
13 alias Pleroma.User
14 alias Pleroma.Web.ActivityPub.ActivityPub
15 alias Pleroma.Web.ActivityPub.Pipeline
16 alias Pleroma.Web.ActivityPub.Utils
17 alias Pleroma.Web.Streamer
18
19 def handle(object, meta \\ [])
20
21 # Tasks this handles:
22 # - Add like to object
23 # - Set up notification
24 def handle(%{data: %{"type" => "Like"}} = object, meta) do
25 liked_object = Object.get_by_ap_id(object.data["object"])
26 Utils.add_like_to_object(object, liked_object)
27
28 Notification.create_notifications(object)
29
30 {:ok, object, meta}
31 end
32
33 # Tasks this handles
34 # - Actually create object
35 # - Rollback if we couldn't create it
36 # - Set up notifications
37 def handle(%{data: %{"type" => "Create"}} = activity, meta) do
38 with {:ok, _object, _meta} <- handle_object_creation(meta[:object_data], meta) do
39 Notification.create_notifications(activity)
40 {:ok, activity, meta}
41 else
42 e -> Repo.rollback(e)
43 end
44 end
45
46 # Tasks this handles:
47 # - Add announce to object
48 # - Set up notification
49 # - Stream out the announce
50 def handle(%{data: %{"type" => "Announce"}} = object, meta) do
51 announced_object = Object.get_by_ap_id(object.data["object"])
52 user = User.get_cached_by_ap_id(object.data["actor"])
53
54 Utils.add_announce_to_object(object, announced_object)
55
56 if !User.is_internal_user?(user) do
57 Notification.create_notifications(object)
58 ActivityPub.stream_out(object)
59 end
60
61 {:ok, object, meta}
62 end
63
64 def handle(%{data: %{"type" => "Undo", "object" => undone_object}} = object, meta) do
65 with undone_object <- Activity.get_by_ap_id(undone_object),
66 :ok <- handle_undoing(undone_object) do
67 {:ok, object, meta}
68 end
69 end
70
71 # Tasks this handles:
72 # - Add reaction to object
73 # - Set up notification
74 def handle(%{data: %{"type" => "EmojiReact"}} = object, meta) do
75 reacted_object = Object.get_by_ap_id(object.data["object"])
76 Utils.add_emoji_reaction_to_object(object, reacted_object)
77
78 Notification.create_notifications(object)
79
80 {:ok, object, meta}
81 end
82
83 # Tasks this handles:
84 # - Delete and unpins the create activity
85 # - Replace object with Tombstone
86 # - Set up notification
87 # - Reduce the user note count
88 # - Reduce the reply count
89 # - Stream out the activity
90 def handle(%{data: %{"type" => "Delete", "object" => deleted_object}} = object, meta) do
91 deleted_object =
92 Object.normalize(deleted_object, false) || User.get_cached_by_ap_id(deleted_object)
93
94 result =
95 case deleted_object do
96 %Object{} ->
97 with {:ok, deleted_object, activity} <- Object.delete(deleted_object),
98 %User{} = user <- User.get_cached_by_ap_id(deleted_object.data["actor"]) do
99 User.remove_pinnned_activity(user, activity)
100
101 {:ok, user} = ActivityPub.decrease_note_count_if_public(user, deleted_object)
102
103 if in_reply_to = deleted_object.data["inReplyTo"] do
104 Object.decrease_replies_count(in_reply_to)
105 end
106
107 ActivityPub.stream_out(object)
108 ActivityPub.stream_out_participations(deleted_object, user)
109 :ok
110 end
111
112 %User{} ->
113 with {:ok, _} <- User.delete(deleted_object) do
114 :ok
115 end
116 end
117
118 if result == :ok do
119 Notification.create_notifications(object)
120 {:ok, object, meta}
121 else
122 {:error, result}
123 end
124 end
125
126 # Nothing to do
127 def handle(object, meta) do
128 {:ok, object, meta}
129 end
130
131 def handle_object_creation(%{"type" => "ChatMessage"} = object, meta) do
132 with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
133 actor = User.get_cached_by_ap_id(object.data["actor"])
134 recipient = User.get_cached_by_ap_id(hd(object.data["to"]))
135
136 [[actor, recipient], [recipient, actor]]
137 |> Enum.each(fn [user, other_user] ->
138 if user.local do
139 if user.ap_id == actor.ap_id do
140 Chat.get_or_create(user.id, other_user.ap_id)
141 else
142 Chat.bump_or_create(user.id, other_user.ap_id)
143 end
144 end
145 end)
146
147 Streamer.stream(["user", "user:pleroma_chat"], object)
148 {:ok, object, meta}
149 end
150 end
151
152 # Nothing to do
153 def handle_object_creation(object) do
154 {:ok, object}
155 end
156
157 def handle_undoing(%{data: %{"type" => "Like"}} = object) do
158 with %Object{} = liked_object <- Object.get_by_ap_id(object.data["object"]),
159 {:ok, _} <- Utils.remove_like_from_object(object, liked_object),
160 {:ok, _} <- Repo.delete(object) do
161 :ok
162 end
163 end
164
165 def handle_undoing(%{data: %{"type" => "EmojiReact"}} = object) do
166 with %Object{} = reacted_object <- Object.get_by_ap_id(object.data["object"]),
167 {:ok, _} <- Utils.remove_emoji_reaction_from_object(object, reacted_object),
168 {:ok, _} <- Repo.delete(object) do
169 :ok
170 end
171 end
172
173 def handle_undoing(%{data: %{"type" => "Announce"}} = object) do
174 with %Object{} = liked_object <- Object.get_by_ap_id(object.data["object"]),
175 {:ok, _} <- Utils.remove_announce_from_object(object, liked_object),
176 {:ok, _} <- Repo.delete(object) do
177 :ok
178 end
179 end
180
181 def handle_undoing(
182 %{data: %{"type" => "Block", "actor" => blocker, "object" => blocked}} = object
183 ) do
184 with %User{} = blocker <- User.get_cached_by_ap_id(blocker),
185 %User{} = blocked <- User.get_cached_by_ap_id(blocked),
186 {:ok, _} <- User.unblock(blocker, blocked),
187 {:ok, _} <- Repo.delete(object) do
188 :ok
189 end
190 end
191
192 def handle_undoing(object), do: {:error, ["don't know how to handle", object]}
193 end