Merge branch 'show-media-endpoint-fixes' into 'develop'
[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 }),
78 me: !!(user && user.ap_id in user_ap_ids)
79 }
80 end
81 end)
82 |> Enum.filter(& &1)
83
84 conn
85 |> json(reactions)
86 else
87 _e ->
88 conn
89 |> json([])
90 end
91 end
92
93 def react_with_emoji(%{assigns: %{user: user}} = conn, %{"id" => activity_id, "emoji" => emoji}) do
94 with {:ok, _activity} <- CommonAPI.react_with_emoji(activity_id, user, emoji),
95 activity <- Activity.get_by_id(activity_id) do
96 conn
97 |> put_view(StatusView)
98 |> render("show.json", %{activity: activity, for: user, as: :activity})
99 end
100 end
101
102 def unreact_with_emoji(%{assigns: %{user: user}} = conn, %{
103 "id" => activity_id,
104 "emoji" => emoji
105 }) do
106 with {:ok, _activity} <-
107 CommonAPI.unreact_with_emoji(activity_id, user, emoji),
108 activity <- Activity.get_by_id(activity_id) do
109 conn
110 |> put_view(StatusView)
111 |> render("show.json", %{activity: activity, for: user, as: :activity})
112 end
113 end
114
115 def conversation(%{assigns: %{user: user}} = conn, %{"id" => participation_id}) do
116 with %Participation{} = participation <- Participation.get(participation_id),
117 true <- user.id == participation.user_id do
118 conn
119 |> put_view(ConversationView)
120 |> render("participation.json", %{participation: participation, for: user})
121 else
122 _error ->
123 conn
124 |> put_status(404)
125 |> json(%{"error" => "Unknown conversation id"})
126 end
127 end
128
129 def conversation_statuses(
130 %{assigns: %{user: %{id: user_id} = user}} = conn,
131 %{"id" => participation_id} = params
132 ) do
133 with %Participation{user_id: ^user_id} = participation <-
134 Participation.get(participation_id, preload: [:conversation]) do
135 params =
136 params
137 |> Map.put("blocking_user", user)
138 |> Map.put("muting_user", user)
139 |> Map.put("user", user)
140
141 activities =
142 participation.conversation.ap_id
143 |> ActivityPub.fetch_activities_for_context_query(params)
144 |> Pleroma.Pagination.fetch_paginated(Map.put(params, "total", false))
145 |> Enum.reverse()
146
147 conn
148 |> add_link_headers(activities)
149 |> put_view(StatusView)
150 |> render("index.json",
151 activities: activities,
152 for: user,
153 as: :activity
154 )
155 else
156 _error ->
157 conn
158 |> put_status(404)
159 |> json(%{"error" => "Unknown conversation id"})
160 end
161 end
162
163 def update_conversation(
164 %{assigns: %{user: user}} = conn,
165 %{"id" => participation_id, "recipients" => recipients}
166 ) do
167 with %Participation{} = participation <- Participation.get(participation_id),
168 true <- user.id == participation.user_id,
169 {:ok, participation} <- Participation.set_recipients(participation, recipients) do
170 conn
171 |> put_view(ConversationView)
172 |> render("participation.json", %{participation: participation, for: user})
173 else
174 {:error, message} ->
175 conn
176 |> put_status(:bad_request)
177 |> json(%{"error" => message})
178
179 _error ->
180 conn
181 |> put_status(404)
182 |> json(%{"error" => "Unknown conversation id"})
183 end
184 end
185
186 def mark_conversations_as_read(%{assigns: %{user: user}} = conn, _params) do
187 with {:ok, _, participations} <- Participation.mark_all_as_read(user) do
188 conn
189 |> add_link_headers(participations)
190 |> put_view(ConversationView)
191 |> render("participations.json", participations: participations, for: user)
192 end
193 end
194
195 def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do
196 with {:ok, notification} <- Notification.read_one(user, notification_id) do
197 conn
198 |> put_view(NotificationView)
199 |> render("show.json", %{notification: notification, for: user})
200 else
201 {:error, message} ->
202 conn
203 |> put_status(:bad_request)
204 |> json(%{"error" => message})
205 end
206 end
207
208 def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{"max_id" => max_id}) do
209 with notifications <- Notification.set_read_up_to(user, max_id) do
210 notifications = Enum.take(notifications, 80)
211
212 conn
213 |> put_view(NotificationView)
214 |> render("index.json",
215 notifications: notifications,
216 for: user
217 )
218 end
219 end
220 end