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