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