1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
6 use Pleroma.Web, :controller
8 import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
10 alias Pleroma.Activity
11 alias Pleroma.Conversation.Participation
12 alias Pleroma.Notification
14 alias Pleroma.Plugs.OAuthScopesPlug
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
23 plug(Pleroma.Web.ApiSpec.CastAndValidate)
27 %{scopes: ["read:statuses"]}
28 when action in [:conversation, :conversation_statuses]
33 %{scopes: ["read:statuses"], fallback: :proceed_unauthenticated}
34 when action == :emoji_reactions_by
39 %{scopes: ["write:statuses"]}
40 when action in [:react_with_emoji, :unreact_with_emoji]
45 %{scopes: ["write:conversations"]}
46 when action in [:update_conversation, :mark_conversations_as_read]
51 %{scopes: ["write:notifications"]} when action == :mark_notifications_as_read
54 defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaOperation
56 def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{id: activity_id} = params) do
57 with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id),
58 %Object{data: %{"reactions" => emoji_reactions}} when is_list(emoji_reactions) <-
59 Object.normalize(activity) do
62 |> Enum.map(fn [emoji, user_ap_ids] ->
63 if params[:emoji] && params[:emoji] != emoji do
67 Enum.map(user_ap_ids, &User.get_cached_by_ap_id/1)
69 %{deactivated: false} -> true
77 AccountView.render("index.json", %{
82 me: !!(user && user.ap_id in user_ap_ids)
86 |> Enum.reject(&is_nil/1)
97 def react_with_emoji(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do
98 with {:ok, _activity} <- CommonAPI.react_with_emoji(activity_id, user, emoji),
99 activity <- Activity.get_by_id(activity_id) do
101 |> put_view(StatusView)
102 |> render("show.json", %{activity: activity, for: user, as: :activity})
106 def unreact_with_emoji(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do
107 with {:ok, _activity} <-
108 CommonAPI.unreact_with_emoji(activity_id, user, emoji),
109 activity <- Activity.get_by_id(activity_id) do
111 |> put_view(StatusView)
112 |> render("show.json", %{activity: activity, for: user, as: :activity})
116 def conversation(%{assigns: %{user: user}} = conn, %{id: participation_id}) do
117 with %Participation{} = participation <- Participation.get(participation_id),
118 true <- user.id == participation.user_id do
120 |> put_view(ConversationView)
121 |> render("participation.json", %{participation: participation, for: user})
126 |> json(%{"error" => "Unknown conversation id"})
130 def conversation_statuses(
131 %{assigns: %{user: %{id: user_id} = user}} = conn,
132 %{id: participation_id} = params
134 with %Participation{user_id: ^user_id} = participation <-
135 Participation.get(participation_id, preload: [:conversation]) do
138 |> Map.new(fn {key, value} -> {to_string(key), value} end)
139 |> Map.put("blocking_user", user)
140 |> Map.put("muting_user", user)
141 |> Map.put("user", user)
144 participation.conversation.ap_id
145 |> ActivityPub.fetch_activities_for_context_query(params)
146 |> Pleroma.Pagination.fetch_paginated(Map.put(params, "total", false))
150 |> add_link_headers(activities)
151 |> put_view(StatusView)
152 |> render("index.json",
153 activities: activities,
161 |> json(%{"error" => "Unknown conversation id"})
165 def update_conversation(
166 %{assigns: %{user: user}} = conn,
167 %{id: participation_id, recipients: recipients}
169 with %Participation{} = participation <- Participation.get(participation_id),
170 true <- user.id == participation.user_id,
171 {:ok, participation} <- Participation.set_recipients(participation, recipients) do
173 |> put_view(ConversationView)
174 |> render("participation.json", %{participation: participation, for: user})
178 |> put_status(:bad_request)
179 |> json(%{"error" => message})
184 |> json(%{"error" => "Unknown conversation id"})
188 def mark_conversations_as_read(%{assigns: %{user: user}} = conn, _params) do
189 with {:ok, _, participations} <- Participation.mark_all_as_read(user) do
191 |> add_link_headers(participations)
192 |> put_view(ConversationView)
193 |> render("participations.json", participations: participations, for: user)
197 def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{id: notification_id}) do
198 with {:ok, notification} <- Notification.read_one(user, notification_id) do
200 |> put_view(NotificationView)
201 |> render("show.json", %{notification: notification, for: user})
205 |> put_status(:bad_request)
206 |> json(%{"error" => message})
210 def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{max_id: max_id}) do
211 with notifications <- Notification.set_read_up_to(user, max_id) do
212 notifications = Enum.take(notifications, 80)
215 |> put_view(NotificationView)
216 |> render("index.json",
217 notifications: notifications,