Merge branch 'feature/change-email' into 'develop'
Add email change endpoint Closes #1156 See merge request pleroma/pleroma!1580
This commit is contained in:
commit
0d9609894f
|
@ -106,6 +106,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- ActivityPub: Optional signing of ActivityPub object fetches.
|
- ActivityPub: Optional signing of ActivityPub object fetches.
|
||||||
- Admin API: Endpoint for fetching latest user's statuses
|
- Admin API: Endpoint for fetching latest user's statuses
|
||||||
- Pleroma API: Add `/api/v1/pleroma/accounts/confirmation_resend?email=<email>` for resending account confirmation.
|
- Pleroma API: Add `/api/v1/pleroma/accounts/confirmation_resend?email=<email>` for resending account confirmation.
|
||||||
|
- Pleroma API: Email change endpoint.
|
||||||
- Relays: Added a task to list relay subscriptions.
|
- Relays: Added a task to list relay subscriptions.
|
||||||
- Mix Tasks: `mix pleroma.database fix_likes_collections`
|
- Mix Tasks: `mix pleroma.database fix_likes_collections`
|
||||||
- Federation: Remove `likes` from objects.
|
- Federation: Remove `likes` from objects.
|
||||||
|
|
|
@ -321,6 +321,16 @@ See [Admin-API](Admin-API.md)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## `/api/pleroma/change_email`
|
||||||
|
### Change account email
|
||||||
|
* Method `POST`
|
||||||
|
* Authentication: required
|
||||||
|
* Params:
|
||||||
|
* `password`: user's password
|
||||||
|
* `email`: new email
|
||||||
|
* Response: JSON. Returns `{"status": "success"}` if the change was successful, `{"error": "[error message]"}` otherwise
|
||||||
|
* Note: Currently, Mastodon has no API for changing email. If they add it in future it might be incompatible with Pleroma.
|
||||||
|
|
||||||
# Pleroma Conversations
|
# Pleroma Conversations
|
||||||
|
|
||||||
Pleroma Conversations have the same general structure that Mastodon Conversations have. The behavior differs in the following ways when using these endpoints:
|
Pleroma Conversations have the same general structure that Mastodon Conversations have. The behavior differs in the following ways when using these endpoints:
|
||||||
|
|
|
@ -1624,4 +1624,13 @@ defp put_password_hash(changeset), do: changeset
|
||||||
def is_internal_user?(%User{nickname: nil}), do: true
|
def is_internal_user?(%User{nickname: nil}), do: true
|
||||||
def is_internal_user?(%User{local: true, nickname: "internal." <> _}), do: true
|
def is_internal_user?(%User{local: true, nickname: "internal." <> _}), do: true
|
||||||
def is_internal_user?(_), do: false
|
def is_internal_user?(_), do: false
|
||||||
|
|
||||||
|
def change_email(user, email) do
|
||||||
|
user
|
||||||
|
|> cast(%{email: email}, [:email])
|
||||||
|
|> validate_required([:email])
|
||||||
|
|> unique_constraint(:email)
|
||||||
|
|> validate_format(:email, @email_regex)
|
||||||
|
|> update_and_set_cache()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -224,6 +224,7 @@ defmodule Pleroma.Web.Router do
|
||||||
scope [] do
|
scope [] do
|
||||||
pipe_through(:oauth_write)
|
pipe_through(:oauth_write)
|
||||||
|
|
||||||
|
post("/change_email", UtilController, :change_email)
|
||||||
post("/change_password", UtilController, :change_password)
|
post("/change_password", UtilController, :change_password)
|
||||||
post("/delete_account", UtilController, :delete_account)
|
post("/delete_account", UtilController, :delete_account)
|
||||||
put("/notification_settings", UtilController, :update_notificaton_settings)
|
put("/notification_settings", UtilController, :update_notificaton_settings)
|
||||||
|
|
|
@ -314,6 +314,25 @@ def change_password(%{assigns: %{user: user}} = conn, params) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def change_email(%{assigns: %{user: user}} = conn, params) do
|
||||||
|
case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
|
||||||
|
{:ok, user} ->
|
||||||
|
with {:ok, _user} <- User.change_email(user, params["email"]) do
|
||||||
|
json(conn, %{status: "success"})
|
||||||
|
else
|
||||||
|
{:error, changeset} ->
|
||||||
|
{_, {error, _}} = Enum.at(changeset.errors, 0)
|
||||||
|
json(conn, %{error: "Email #{error}."})
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
json(conn, %{error: "Unable to change email."})
|
||||||
|
end
|
||||||
|
|
||||||
|
{:error, msg} ->
|
||||||
|
json(conn, %{error: msg})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def delete_account(%{assigns: %{user: user}} = conn, params) do
|
def delete_account(%{assigns: %{user: user}} = conn, params) do
|
||||||
case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
|
case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
|
||||||
{:ok, user} ->
|
{:ok, user} ->
|
||||||
|
|
|
@ -1614,4 +1614,31 @@ test "syncronizes the counters with the remote instance for the follower when en
|
||||||
assert User.user_info(other_user).following_count == 152
|
assert User.user_info(other_user).following_count == 152
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "change_email/2" do
|
||||||
|
setup do
|
||||||
|
[user: insert(:user)]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "blank email returns error", %{user: user} do
|
||||||
|
assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
|
||||||
|
assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "non unique email returns error", %{user: user} do
|
||||||
|
%{email: email} = insert(:user)
|
||||||
|
|
||||||
|
assert {:error, %{errors: [email: {"has already been taken", _}]}} =
|
||||||
|
User.change_email(user, email)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "invalid email returns error", %{user: user} do
|
||||||
|
assert {:error, %{errors: [email: {"has invalid format", _}]}} =
|
||||||
|
User.change_email(user, "cofe")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "changes email", %{user: user} do
|
||||||
|
assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -662,4 +662,111 @@ test "it returns new captcha", %{conn: conn} do
|
||||||
assert called(Pleroma.Captcha.new())
|
assert called(Pleroma.Captcha.new())
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp with_credentials(conn, username, password) do
|
||||||
|
header_content = "Basic " <> Base.encode64("#{username}:#{password}")
|
||||||
|
put_req_header(conn, "authorization", header_content)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp valid_user(_context) do
|
||||||
|
user = insert(:user)
|
||||||
|
[user: user]
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "POST /api/pleroma/change_email" do
|
||||||
|
setup [:valid_user]
|
||||||
|
|
||||||
|
test "without credentials", %{conn: conn} do
|
||||||
|
conn = post(conn, "/api/pleroma/change_email")
|
||||||
|
assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "with credentials and invalid password", %{conn: conn, user: current_user} do
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> with_credentials(current_user.nickname, "test")
|
||||||
|
|> post("/api/pleroma/change_email", %{
|
||||||
|
"password" => "hi",
|
||||||
|
"email" => "test@test.com"
|
||||||
|
})
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == %{"error" => "Invalid password."}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "with credentials, valid password and invalid email", %{
|
||||||
|
conn: conn,
|
||||||
|
user: current_user
|
||||||
|
} do
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> with_credentials(current_user.nickname, "test")
|
||||||
|
|> post("/api/pleroma/change_email", %{
|
||||||
|
"password" => "test",
|
||||||
|
"email" => "foobar"
|
||||||
|
})
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == %{"error" => "Email has invalid format."}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "with credentials, valid password and no email", %{
|
||||||
|
conn: conn,
|
||||||
|
user: current_user
|
||||||
|
} do
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> with_credentials(current_user.nickname, "test")
|
||||||
|
|> post("/api/pleroma/change_email", %{
|
||||||
|
"password" => "test"
|
||||||
|
})
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == %{"error" => "Email can't be blank."}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "with credentials, valid password and blank email", %{
|
||||||
|
conn: conn,
|
||||||
|
user: current_user
|
||||||
|
} do
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> with_credentials(current_user.nickname, "test")
|
||||||
|
|> post("/api/pleroma/change_email", %{
|
||||||
|
"password" => "test",
|
||||||
|
"email" => ""
|
||||||
|
})
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == %{"error" => "Email can't be blank."}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "with credentials, valid password and non unique email", %{
|
||||||
|
conn: conn,
|
||||||
|
user: current_user
|
||||||
|
} do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> with_credentials(current_user.nickname, "test")
|
||||||
|
|> post("/api/pleroma/change_email", %{
|
||||||
|
"password" => "test",
|
||||||
|
"email" => user.email
|
||||||
|
})
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == %{"error" => "Email has already been taken."}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "with credentials, valid password and valid email", %{
|
||||||
|
conn: conn,
|
||||||
|
user: current_user
|
||||||
|
} do
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> with_credentials(current_user.nickname, "test")
|
||||||
|
|> post("/api/pleroma/change_email", %{
|
||||||
|
"password" => "test",
|
||||||
|
"email" => "cofe@foobar.com"
|
||||||
|
})
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == %{"status" => "success"}
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue