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