Update majic & call plug before OpenApiSpex
[akkoma] / lib / pleroma / web / pleroma_api / controllers / account_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.AccountController do
6 use Pleroma.Web, :controller
7
8 import Pleroma.Web.ControllerHelper,
9 only: [json_response: 3, add_link_headers: 2, assign_account_by_id: 2]
10
11 alias Ecto.Changeset
12 alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
13 alias Pleroma.Plugs.OAuthScopesPlug
14 alias Pleroma.Plugs.RateLimiter
15 alias Pleroma.User
16 alias Pleroma.Web.ActivityPub.ActivityPub
17 alias Pleroma.Web.MastodonAPI.StatusView
18
19 require Pleroma.Constants
20
21 plug(
22 Majic.Plug,
23 [pool: Pleroma.MajicPool] when action in [:update_avatar, :update_background, :update_banner]
24 )
25
26 plug(
27 OpenApiSpex.Plug.PutApiSpec,
28 [module: Pleroma.Web.ApiSpec] when action == :confirmation_resend
29 )
30
31 plug(Pleroma.Web.ApiSpec.CastAndValidate)
32
33 plug(
34 :skip_plug,
35 [OAuthScopesPlug, EnsurePublicOrAuthenticatedPlug] when action == :confirmation_resend
36 )
37
38 plug(
39 OAuthScopesPlug,
40 %{scopes: ["follow", "write:follows"]} when action in [:subscribe, :unsubscribe]
41 )
42
43 plug(
44 OAuthScopesPlug,
45 %{scopes: ["write:accounts"]}
46 # Note: the following actions are not permission-secured in Mastodon:
47 when action in [
48 :update_avatar,
49 :update_banner,
50 :update_background
51 ]
52 )
53
54 plug(
55 OAuthScopesPlug,
56 %{scopes: ["read:favourites"], fallback: :proceed_unauthenticated} when action == :favourites
57 )
58
59 plug(RateLimiter, [name: :account_confirmation_resend] when action == :confirmation_resend)
60
61 plug(:assign_account_by_id when action in [:favourites, :subscribe, :unsubscribe])
62 plug(:put_view, Pleroma.Web.MastodonAPI.AccountView)
63
64 defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaAccountOperation
65
66 @doc "POST /api/v1/pleroma/accounts/confirmation_resend"
67 def confirmation_resend(conn, params) do
68 nickname_or_email = params[:email] || params[:nickname]
69
70 with %User{} = user <- User.get_by_nickname_or_email(nickname_or_email),
71 {:ok, _} <- User.try_send_confirmation_email(user) do
72 json_response(conn, :no_content, "")
73 end
74 end
75
76 @doc "PATCH /api/v1/pleroma/accounts/update_avatar"
77 def update_avatar(%{assigns: %{user: user}, body_params: %{img: ""}} = conn, _) do
78 {:ok, _user} =
79 user
80 |> Changeset.change(%{avatar: nil})
81 |> User.update_and_set_cache()
82
83 json(conn, %{url: nil})
84 end
85
86 def update_avatar(%{assigns: %{user: user}, body_params: params} = conn, _params) do
87 {:ok, %{data: data}} = ActivityPub.upload(params, type: :avatar)
88 {:ok, _user} = user |> Changeset.change(%{avatar: data}) |> User.update_and_set_cache()
89 %{"url" => [%{"href" => href} | _]} = data
90
91 json(conn, %{url: href})
92 end
93
94 @doc "PATCH /api/v1/pleroma/accounts/update_banner"
95 def update_banner(%{assigns: %{user: user}, body_params: %{banner: ""}} = conn, _) do
96 with {:ok, _user} <- User.update_banner(user, %{}) do
97 json(conn, %{url: nil})
98 end
99 end
100
101 def update_banner(%{assigns: %{user: user}, body_params: params} = conn, _) do
102 with {:ok, object} <- ActivityPub.upload(%{img: params[:banner]}, type: :banner),
103 {:ok, _user} <- User.update_banner(user, object.data) do
104 %{"url" => [%{"href" => href} | _]} = object.data
105
106 json(conn, %{url: href})
107 end
108 end
109
110 @doc "PATCH /api/v1/pleroma/accounts/update_background"
111 def update_background(%{assigns: %{user: user}, body_params: %{img: ""}} = conn, _) do
112 with {:ok, _user} <- User.update_background(user, %{}) do
113 json(conn, %{url: nil})
114 end
115 end
116
117 def update_background(%{assigns: %{user: user}, body_params: params} = conn, _) do
118 with {:ok, object} <- ActivityPub.upload(params, type: :background),
119 {:ok, _user} <- User.update_background(user, object.data) do
120 %{"url" => [%{"href" => href} | _]} = object.data
121
122 json(conn, %{url: href})
123 end
124 end
125
126 @doc "GET /api/v1/pleroma/accounts/:id/favourites"
127 def favourites(%{assigns: %{account: %{hide_favorites: true}}} = conn, _params) do
128 render_error(conn, :forbidden, "Can't get favorites")
129 end
130
131 def favourites(%{assigns: %{user: for_user, account: user}} = conn, params) do
132 params =
133 params
134 |> Map.put(:type, "Create")
135 |> Map.put(:favorited_by, user.ap_id)
136 |> Map.put(:blocking_user, for_user)
137
138 recipients =
139 if for_user do
140 [Pleroma.Constants.as_public()] ++ [for_user.ap_id | User.following(for_user)]
141 else
142 [Pleroma.Constants.as_public()]
143 end
144
145 activities =
146 recipients
147 |> ActivityPub.fetch_activities(params)
148 |> Enum.reverse()
149
150 conn
151 |> add_link_headers(activities)
152 |> put_view(StatusView)
153 |> render("index.json",
154 activities: activities,
155 for: for_user,
156 as: :activity
157 )
158 end
159
160 @doc "POST /api/v1/pleroma/accounts/:id/subscribe"
161 def subscribe(%{assigns: %{user: user, account: subscription_target}} = conn, _params) do
162 with {:ok, _subscription} <- User.subscribe(user, subscription_target) do
163 render(conn, "relationship.json", user: user, target: subscription_target)
164 else
165 {:error, message} -> json_response(conn, :forbidden, %{error: message})
166 end
167 end
168
169 @doc "POST /api/v1/pleroma/accounts/:id/unsubscribe"
170 def unsubscribe(%{assigns: %{user: user, account: subscription_target}} = conn, _params) do
171 with {:ok, _subscription} <- User.unsubscribe(user, subscription_target) do
172 render(conn, "relationship.json", user: user, target: subscription_target)
173 else
174 {:error, message} -> json_response(conn, :forbidden, %{error: message})
175 end
176 end
177 end