Merge branch 'emoji-reactions-reacted' 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}) 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 users =
52 Enum.map(user_ap_ids, &User.get_cached_by_ap_id/1)
53 |> Enum.filter(& &1)
54
55 %{
56 emoji: emoji,
57 count: length(users),
58 accounts: AccountView.render("index.json", %{users: users, for: user, as: :user}),
59 reacted: !!(user && user.ap_id in user_ap_ids)
60 }
61 end)
62
63 conn
64 |> json(reactions)
65 else
66 _e ->
67 conn
68 |> json([])
69 end
70 end
71
72 def react_with_emoji(%{assigns: %{user: user}} = conn, %{"id" => activity_id, "emoji" => emoji}) do
73 with {:ok, _activity, _object} <- CommonAPI.react_with_emoji(activity_id, user, emoji),
74 activity <- Activity.get_by_id(activity_id) do
75 conn
76 |> put_view(StatusView)
77 |> render("show.json", %{activity: activity, for: user, as: :activity})
78 end
79 end
80
81 def unreact_with_emoji(%{assigns: %{user: user}} = conn, %{
82 "id" => activity_id,
83 "emoji" => emoji
84 }) do
85 with {:ok, _activity, _object} <- CommonAPI.unreact_with_emoji(activity_id, user, emoji),
86 activity <- Activity.get_by_id(activity_id) do
87 conn
88 |> put_view(StatusView)
89 |> render("show.json", %{activity: activity, for: user, as: :activity})
90 end
91 end
92
93 def conversation(%{assigns: %{user: user}} = conn, %{"id" => participation_id}) do
94 with %Participation{} = participation <- Participation.get(participation_id),
95 true <- user.id == participation.user_id do
96 conn
97 |> put_view(ConversationView)
98 |> render("participation.json", %{participation: participation, for: user})
99 end
100 end
101
102 def conversation_statuses(
103 %{assigns: %{user: user}} = conn,
104 %{"id" => participation_id} = params
105 ) do
106 participation = Participation.get(participation_id, preload: [:conversation])
107
108 if user.id == participation.user_id do
109 params =
110 params
111 |> Map.put("blocking_user", user)
112 |> Map.put("muting_user", user)
113 |> Map.put("user", user)
114
115 activities =
116 participation.conversation.ap_id
117 |> ActivityPub.fetch_activities_for_context(params)
118 |> Enum.reverse()
119
120 conn
121 |> add_link_headers(activities)
122 |> put_view(StatusView)
123 |> render("index.json", %{activities: activities, for: user, as: :activity})
124 end
125 end
126
127 def update_conversation(
128 %{assigns: %{user: user}} = conn,
129 %{"id" => participation_id, "recipients" => recipients}
130 ) do
131 participation =
132 participation_id
133 |> Participation.get()
134
135 with true <- user.id == participation.user_id,
136 {:ok, participation} <- Participation.set_recipients(participation, recipients) do
137 conn
138 |> put_view(ConversationView)
139 |> render("participation.json", %{participation: participation, for: user})
140 end
141 end
142
143 def read_conversations(%{assigns: %{user: user}} = conn, _params) do
144 with {:ok, _, participations} <- Participation.mark_all_as_read(user) do
145 conn
146 |> add_link_headers(participations)
147 |> put_view(ConversationView)
148 |> render("participations.json", participations: participations, for: user)
149 end
150 end
151
152 def read_notification(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do
153 with {:ok, notification} <- Notification.read_one(user, notification_id) do
154 conn
155 |> put_view(NotificationView)
156 |> render("show.json", %{notification: notification, for: user})
157 else
158 {:error, message} ->
159 conn
160 |> put_status(:bad_request)
161 |> json(%{"error" => message})
162 end
163 end
164
165 def read_notification(%{assigns: %{user: user}} = conn, %{"max_id" => max_id}) do
166 with notifications <- Notification.set_read_up_to(user, max_id) do
167 notifications = Enum.take(notifications, 80)
168
169 conn
170 |> put_view(NotificationView)
171 |> render("index.json", %{notifications: notifications, for: user})
172 end
173 end
174 end