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