Merge branch 'migration-fixes-20' into 'develop'
[akkoma] / lib / pleroma / web / pleroma_api / controllers / pleroma_api_controller.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 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: ["write:statuses"]}
32 when action in [:react_with_emoji, :unreact_with_emoji]
33 )
34
35 plug(
36 OAuthScopesPlug,
37 %{scopes: ["write:conversations"]} when action == :update_conversation
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 end
105 end
106
107 def conversation_statuses(
108 %{assigns: %{user: user}} = conn,
109 %{"id" => participation_id} = params
110 ) do
111 participation = Participation.get(participation_id, preload: [:conversation])
112
113 if user.id == participation.user_id do
114 params =
115 params
116 |> Map.put("blocking_user", user)
117 |> Map.put("muting_user", user)
118 |> Map.put("user", user)
119
120 activities =
121 participation.conversation.ap_id
122 |> ActivityPub.fetch_activities_for_context(params)
123 |> Enum.reverse()
124
125 conn
126 |> add_link_headers(activities)
127 |> put_view(StatusView)
128 |> render("index.json", %{activities: activities, for: user, as: :activity})
129 end
130 end
131
132 def update_conversation(
133 %{assigns: %{user: user}} = conn,
134 %{"id" => participation_id, "recipients" => recipients}
135 ) do
136 participation =
137 participation_id
138 |> Participation.get()
139
140 with true <- user.id == participation.user_id,
141 {:ok, participation} <- Participation.set_recipients(participation, recipients) do
142 conn
143 |> put_view(ConversationView)
144 |> render("participation.json", %{participation: participation, for: user})
145 end
146 end
147
148 def read_conversations(%{assigns: %{user: user}} = conn, _params) do
149 with {:ok, _, participations} <- Participation.mark_all_as_read(user) do
150 conn
151 |> add_link_headers(participations)
152 |> put_view(ConversationView)
153 |> render("participations.json", participations: participations, for: user)
154 end
155 end
156
157 def read_notification(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do
158 with {:ok, notification} <- Notification.read_one(user, notification_id) do
159 conn
160 |> put_view(NotificationView)
161 |> render("show.json", %{notification: notification, for: user})
162 else
163 {:error, message} ->
164 conn
165 |> put_status(:bad_request)
166 |> json(%{"error" => message})
167 end
168 end
169
170 def read_notification(%{assigns: %{user: user}} = conn, %{"max_id" => max_id}) do
171 with notifications <- Notification.set_read_up_to(user, max_id) do
172 notifications = Enum.take(notifications, 80)
173
174 conn
175 |> put_view(NotificationView)
176 |> render("index.json", %{notifications: notifications, for: user})
177 end
178 end
179 end