02296b210562679f1dfb7e3c0c7065f67cfde9e3
[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
53 Utils.add_announce_to_object(object, announced_object)
54
55 Notification.create_notifications(object)
56 ActivityPub.stream_out(object)
57
58 {:ok, object, meta}
59 end
60
61 def handle(%{data: %{"type" => "Undo", "object" => undone_object}} = object, meta) do
62 with undone_object <- Activity.get_by_ap_id(undone_object),
63 :ok <- handle_undoing(undone_object) do
64 {:ok, object, meta}
65 end
66 end
67
68 # Tasks this handles:
69 # - Add reaction to object
70 # - Set up notification
71 def handle(%{data: %{"type" => "EmojiReact"}} = object, meta) do
72 reacted_object = Object.get_by_ap_id(object.data["object"])
73 Utils.add_emoji_reaction_to_object(object, reacted_object)
74
75 Notification.create_notifications(object)
76
77 {:ok, object, meta}
78 end
79
80 # Tasks this handles:
81 # - Delete and unpins the create activity
82 # - Replace object with Tombstone
83 # - Set up notification
84 # - Reduce the user note count
85 # - Reduce the reply count
86 # - Stream out the activity
87 def handle(%{data: %{"type" => "Delete", "object" => deleted_object}} = object, meta) do
88 deleted_object =
89 Object.normalize(deleted_object, false) || User.get_cached_by_ap_id(deleted_object)
90
91 result =
92 case deleted_object do
93 %Object{} ->
94 with {:ok, deleted_object, activity} <- Object.delete(deleted_object),
95 %User{} = user <- User.get_cached_by_ap_id(deleted_object.data["actor"]) do
96 User.remove_pinnned_activity(user, activity)
97
98 {:ok, user} = ActivityPub.decrease_note_count_if_public(user, deleted_object)
99
100 if in_reply_to = deleted_object.data["inReplyTo"] do
101 Object.decrease_replies_count(in_reply_to)
102 end
103
104 ActivityPub.stream_out(object)
105 ActivityPub.stream_out_participations(deleted_object, user)
106 :ok
107 end
108
109 %User{} ->
110 with {:ok, _} <- User.delete(deleted_object) do
111 :ok
112 end
113 end
114
115 if result == :ok do
116 Notification.create_notifications(object)
117 {:ok, object, meta}
118 else
119 {:error, result}
120 end
121 end
122
123 # Nothing to do
124 def handle(object, meta) do
125 {:ok, object, meta}
126 end
127
128 def handle_object_creation(%{"type" => "ChatMessage"} = object, meta) do
129 with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
130 actor = User.get_cached_by_ap_id(object.data["actor"])
131 recipient = User.get_cached_by_ap_id(hd(object.data["to"]))
132
133 [[actor, recipient], [recipient, actor]]
134 |> Enum.each(fn [user, other_user] ->
135 if user.local do
136 if user.ap_id == actor.ap_id do
137 Chat.get_or_create(user.id, other_user.ap_id)
138 else
139 Chat.bump_or_create(user.id, other_user.ap_id)
140 end
141 end
142 end)
143
144 Streamer.stream(["user", "user:pleroma_chat"], object)
145 {:ok, object, meta}
146 end
147 end
148
149 # Nothing to do
150 def handle_object_creation(object) do
151 {:ok, object}
152 end
153
154 def handle_undoing(%{data: %{"type" => "Like"}} = object) do
155 with %Object{} = liked_object <- Object.get_by_ap_id(object.data["object"]),
156 {:ok, _} <- Utils.remove_like_from_object(object, liked_object),
157 {:ok, _} <- Repo.delete(object) do
158 :ok
159 end
160 end
161
162 def handle_undoing(%{data: %{"type" => "EmojiReact"}} = object) do
163 with %Object{} = reacted_object <- Object.get_by_ap_id(object.data["object"]),
164 {:ok, _} <- Utils.remove_emoji_reaction_from_object(object, reacted_object),
165 {:ok, _} <- Repo.delete(object) do
166 :ok
167 end
168 end
169
170 def handle_undoing(%{data: %{"type" => "Announce"}} = object) do
171 with %Object{} = liked_object <- Object.get_by_ap_id(object.data["object"]),
172 {:ok, _} <- Utils.remove_announce_from_object(object, liked_object),
173 {:ok, _} <- Repo.delete(object) do
174 :ok
175 end
176 end
177
178 def handle_undoing(
179 %{data: %{"type" => "Block", "actor" => blocker, "object" => blocked}} = object
180 ) do
181 with %User{} = blocker <- User.get_cached_by_ap_id(blocker),
182 %User{} = blocked <- User.get_cached_by_ap_id(blocked),
183 {:ok, _} <- User.unblock(blocker, blocked),
184 {:ok, _} <- Repo.delete(object) do
185 :ok
186 end
187 end
188
189 def handle_undoing(object), do: {:error, ["don't know how to handle", object]}
190 end