Automatic checks of authentication / instance publicity. Definition of missing OAuth...
[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, skip_relationships?: 1]
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: ["write:statuses"]}
32 when action in [:react_with_emoji, :unreact_with_emoji]
33 )
34
35 plug(
36 OAuthScopesPlug,
37 %{scopes: ["write:conversations"]}
38 when action in [:update_conversation, :mark_conversations_as_read]
39 )
40
41 plug(
42 OAuthScopesPlug,
43 %{scopes: ["write:notifications"]} when action == :mark_notifications_as_read
44 )
45
46 def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id} = params) do
47 with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id),
48 %Object{data: %{"reactions" => emoji_reactions}} when is_list(emoji_reactions) <-
49 Object.normalize(activity) do
50 reactions =
51 emoji_reactions
52 |> Enum.map(fn [emoji, user_ap_ids] ->
53 if params["emoji"] && params["emoji"] != emoji do
54 nil
55 else
56 users =
57 Enum.map(user_ap_ids, &User.get_cached_by_ap_id/1)
58 |> Enum.filter(& &1)
59
60 %{
61 name: emoji,
62 count: length(users),
63 accounts: AccountView.render("index.json", %{users: users, for: user, as: :user}),
64 me: !!(user && user.ap_id in user_ap_ids)
65 }
66 end
67 end)
68 |> Enum.filter(& &1)
69
70 conn
71 |> json(reactions)
72 else
73 _e ->
74 conn
75 |> json([])
76 end
77 end
78
79 def react_with_emoji(%{assigns: %{user: user}} = conn, %{"id" => activity_id, "emoji" => emoji}) do
80 with {:ok, _activity, _object} <- CommonAPI.react_with_emoji(activity_id, user, emoji),
81 activity <- Activity.get_by_id(activity_id) do
82 conn
83 |> put_view(StatusView)
84 |> render("show.json", %{activity: activity, for: user, as: :activity})
85 end
86 end
87
88 def unreact_with_emoji(%{assigns: %{user: user}} = conn, %{
89 "id" => activity_id,
90 "emoji" => emoji
91 }) do
92 with {:ok, _activity, _object} <- CommonAPI.unreact_with_emoji(activity_id, user, emoji),
93 activity <- Activity.get_by_id(activity_id) do
94 conn
95 |> put_view(StatusView)
96 |> render("show.json", %{activity: activity, for: user, as: :activity})
97 end
98 end
99
100 def conversation(%{assigns: %{user: user}} = conn, %{"id" => participation_id}) do
101 with %Participation{} = participation <- Participation.get(participation_id),
102 true <- user.id == participation.user_id do
103 conn
104 |> put_view(ConversationView)
105 |> render("participation.json", %{participation: participation, for: user})
106 else
107 _error ->
108 conn
109 |> put_status(404)
110 |> json(%{"error" => "Unknown conversation id"})
111 end
112 end
113
114 def conversation_statuses(
115 %{assigns: %{user: %{id: user_id} = user}} = conn,
116 %{"id" => participation_id} = params
117 ) do
118 with %Participation{user_id: ^user_id} = participation <-
119 Participation.get(participation_id, preload: [:conversation]) do
120 params =
121 params
122 |> Map.put("blocking_user", user)
123 |> Map.put("muting_user", user)
124 |> Map.put("user", user)
125
126 activities =
127 participation.conversation.ap_id
128 |> ActivityPub.fetch_activities_for_context_query(params)
129 |> Pleroma.Pagination.fetch_paginated(Map.put(params, "total", false))
130 |> Enum.reverse()
131
132 conn
133 |> add_link_headers(activities)
134 |> put_view(StatusView)
135 |> render("index.json",
136 activities: activities,
137 for: user,
138 as: :activity,
139 skip_relationships: skip_relationships?(params)
140 )
141 else
142 _error ->
143 conn
144 |> put_status(404)
145 |> json(%{"error" => "Unknown conversation id"})
146 end
147 end
148
149 def update_conversation(
150 %{assigns: %{user: user}} = conn,
151 %{"id" => participation_id, "recipients" => recipients}
152 ) do
153 with %Participation{} = participation <- Participation.get(participation_id),
154 true <- user.id == participation.user_id,
155 {:ok, participation} <- Participation.set_recipients(participation, recipients) do
156 conn
157 |> put_view(ConversationView)
158 |> render("participation.json", %{participation: participation, for: user})
159 else
160 {:error, message} ->
161 conn
162 |> put_status(:bad_request)
163 |> json(%{"error" => message})
164
165 _error ->
166 conn
167 |> put_status(404)
168 |> json(%{"error" => "Unknown conversation id"})
169 end
170 end
171
172 def mark_conversations_as_read(%{assigns: %{user: user}} = conn, _params) do
173 with {:ok, _, participations} <- Participation.mark_all_as_read(user) do
174 conn
175 |> add_link_headers(participations)
176 |> put_view(ConversationView)
177 |> render("participations.json", participations: participations, for: user)
178 end
179 end
180
181 def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do
182 with {:ok, notification} <- Notification.read_one(user, notification_id) do
183 conn
184 |> put_view(NotificationView)
185 |> render("show.json", %{notification: notification, for: user})
186 else
187 {:error, message} ->
188 conn
189 |> put_status(:bad_request)
190 |> json(%{"error" => message})
191 end
192 end
193
194 def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{"max_id" => max_id} = params) do
195 with notifications <- Notification.set_read_up_to(user, max_id) do
196 notifications = Enum.take(notifications, 80)
197
198 conn
199 |> put_view(NotificationView)
200 |> render("index.json",
201 notifications: notifications,
202 for: user,
203 skip_relationships: skip_relationships?(params)
204 )
205 end
206 end
207 end