[#2456] Dropped support for embedded `pleroma/account/relationship` in statuses and...
[akkoma] / lib / pleroma / web / pleroma_api / controllers / pleroma_api_controller.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
6 use Pleroma.Web, :controller
7
8 import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
9
10 alias Pleroma.Activity
11 alias Pleroma.Conversation.Participation
12 alias Pleroma.Notification
13 alias Pleroma.Object
14 alias Pleroma.Plugs.OAuthScopesPlug
15 alias Pleroma.User
16 alias Pleroma.Web.ActivityPub.ActivityPub
17 alias Pleroma.Web.CommonAPI
18 alias Pleroma.Web.MastodonAPI.AccountView
19 alias Pleroma.Web.MastodonAPI.ConversationView
20 alias Pleroma.Web.MastodonAPI.NotificationView
21 alias Pleroma.Web.MastodonAPI.StatusView
22
23 plug(
24 OAuthScopesPlug,
25 %{scopes: ["read:statuses"]}
26 when action in [:conversation, :conversation_statuses]
27 )
28
29 plug(
30 OAuthScopesPlug,
31 %{scopes: ["read:statuses"], fallback: :proceed_unauthenticated}
32 when action == :emoji_reactions_by
33 )
34
35 plug(
36 OAuthScopesPlug,
37 %{scopes: ["write:statuses"]}
38 when action in [:react_with_emoji, :unreact_with_emoji]
39 )
40
41 plug(
42 OAuthScopesPlug,
43 %{scopes: ["write:conversations"]}
44 when action in [:update_conversation, :mark_conversations_as_read]
45 )
46
47 plug(
48 OAuthScopesPlug,
49 %{scopes: ["write:notifications"]} when action == :mark_notifications_as_read
50 )
51
52 def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id} = params) do
53 with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id),
54 %Object{data: %{"reactions" => emoji_reactions}} when is_list(emoji_reactions) <-
55 Object.normalize(activity) do
56 reactions =
57 emoji_reactions
58 |> Enum.map(fn [emoji, user_ap_ids] ->
59 if params["emoji"] && params["emoji"] != emoji do
60 nil
61 else
62 users =
63 Enum.map(user_ap_ids, &User.get_cached_by_ap_id/1)
64 |> Enum.filter(fn
65 %{deactivated: false} -> true
66 _ -> false
67 end)
68
69 %{
70 name: emoji,
71 count: length(users),
72 accounts:
73 AccountView.render("index.json", %{
74 users: users,
75 for: user,
76 as: :user,
77 skip_relationships: true
78 }),
79 me: !!(user && user.ap_id in user_ap_ids)
80 }
81 end
82 end)
83 |> Enum.filter(& &1)
84
85 conn
86 |> json(reactions)
87 else
88 _e ->
89 conn
90 |> json([])
91 end
92 end
93
94 def react_with_emoji(%{assigns: %{user: user}} = conn, %{"id" => activity_id, "emoji" => emoji}) do
95 with {:ok, _activity} <- CommonAPI.react_with_emoji(activity_id, user, emoji),
96 activity <- Activity.get_by_id(activity_id) do
97 conn
98 |> put_view(StatusView)
99 |> render("show.json", %{activity: activity, for: user, as: :activity})
100 end
101 end
102
103 def unreact_with_emoji(%{assigns: %{user: user}} = conn, %{
104 "id" => activity_id,
105 "emoji" => emoji
106 }) do
107 with {:ok, _activity} <-
108 CommonAPI.unreact_with_emoji(activity_id, user, emoji),
109 activity <- Activity.get_by_id(activity_id) do
110 conn
111 |> put_view(StatusView)
112 |> render("show.json", %{activity: activity, for: user, as: :activity})
113 end
114 end
115
116 def conversation(%{assigns: %{user: user}} = conn, %{"id" => participation_id}) do
117 with %Participation{} = participation <- Participation.get(participation_id),
118 true <- user.id == participation.user_id do
119 conn
120 |> put_view(ConversationView)
121 |> render("participation.json", %{participation: participation, for: user})
122 else
123 _error ->
124 conn
125 |> put_status(404)
126 |> json(%{"error" => "Unknown conversation id"})
127 end
128 end
129
130 def conversation_statuses(
131 %{assigns: %{user: %{id: user_id} = user}} = conn,
132 %{"id" => participation_id} = params
133 ) do
134 with %Participation{user_id: ^user_id} = participation <-
135 Participation.get(participation_id, preload: [:conversation]) do
136 params =
137 params
138 |> Map.put("blocking_user", user)
139 |> Map.put("muting_user", user)
140 |> Map.put("user", user)
141
142 activities =
143 participation.conversation.ap_id
144 |> ActivityPub.fetch_activities_for_context_query(params)
145 |> Pleroma.Pagination.fetch_paginated(Map.put(params, "total", false))
146 |> Enum.reverse()
147
148 conn
149 |> add_link_headers(activities)
150 |> put_view(StatusView)
151 |> render("index.json",
152 activities: activities,
153 for: user,
154 as: :activity
155 )
156 else
157 _error ->
158 conn
159 |> put_status(404)
160 |> json(%{"error" => "Unknown conversation id"})
161 end
162 end
163
164 def update_conversation(
165 %{assigns: %{user: user}} = conn,
166 %{"id" => participation_id, "recipients" => recipients}
167 ) do
168 with %Participation{} = participation <- Participation.get(participation_id),
169 true <- user.id == participation.user_id,
170 {:ok, participation} <- Participation.set_recipients(participation, recipients) do
171 conn
172 |> put_view(ConversationView)
173 |> render("participation.json", %{participation: participation, for: user})
174 else
175 {:error, message} ->
176 conn
177 |> put_status(:bad_request)
178 |> json(%{"error" => message})
179
180 _error ->
181 conn
182 |> put_status(404)
183 |> json(%{"error" => "Unknown conversation id"})
184 end
185 end
186
187 def mark_conversations_as_read(%{assigns: %{user: user}} = conn, _params) do
188 with {:ok, _, participations} <- Participation.mark_all_as_read(user) do
189 conn
190 |> add_link_headers(participations)
191 |> put_view(ConversationView)
192 |> render("participations.json", participations: participations, for: user)
193 end
194 end
195
196 def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do
197 with {:ok, notification} <- Notification.read_one(user, notification_id) do
198 conn
199 |> put_view(NotificationView)
200 |> render("show.json", %{notification: notification, for: user})
201 else
202 {:error, message} ->
203 conn
204 |> put_status(:bad_request)
205 |> json(%{"error" => message})
206 end
207 end
208
209 def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{"max_id" => max_id}) do
210 with notifications <- Notification.set_read_up_to(user, max_id) do
211 notifications = Enum.take(notifications, 80)
212
213 conn
214 |> put_view(NotificationView)
215 |> render("index.json",
216 notifications: notifications,
217 for: user
218 )
219 end
220 end
221 end