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