mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-30 14:57:59 +01:00
add button for mods to unlock account (derpibooru/philomena#173)
This commit is contained in:
parent
dbfdd22ea9
commit
6915d2ed45
6 changed files with 80 additions and 7 deletions
|
@ -234,7 +234,7 @@ defmodule Philomena.Users do
|
|||
If the token matches, the user is marked as unlocked
|
||||
and the token is deleted.
|
||||
"""
|
||||
def unlock_user(token) do
|
||||
def unlock_user_by_token(token) do
|
||||
with {:ok, query} <- UserToken.verify_email_token_query(token, "unlock"),
|
||||
%User{} = user <- Repo.one(query),
|
||||
{:ok, %{user: user}} <- Repo.transaction(unlock_user_multi(user)) do
|
||||
|
@ -252,6 +252,15 @@ defmodule Philomena.Users do
|
|||
|> Ecto.Multi.delete_all(:tokens, UserToken.user_and_contexts_query(user, ["unlock"]))
|
||||
end
|
||||
|
||||
@doc """
|
||||
Unconditionally unlocks the given user.
|
||||
"""
|
||||
def unlock_user(user) do
|
||||
user
|
||||
|> User.unlock_changeset()
|
||||
|> Repo.update()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Delivers the unlock instructions to the given user.
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
defmodule PhilomenaWeb.Admin.User.UnlockController do
|
||||
use PhilomenaWeb, :controller
|
||||
|
||||
alias Philomena.Users.User
|
||||
alias Philomena.Users
|
||||
|
||||
plug :verify_authorized
|
||||
plug :load_resource, model: User, id_name: "user_id", id_field: "slug", persisted: true
|
||||
|
||||
def create(conn, _params) do
|
||||
{:ok, user} = Users.unlock_user(conn.assigns.user)
|
||||
|
||||
conn
|
||||
|> put_flash(:info, "User was unlocked.")
|
||||
|> redirect(to: Routes.profile_path(conn, :show, user))
|
||||
end
|
||||
|
||||
defp verify_authorized(conn, _opts) do
|
||||
case Canada.Can.can?(conn.assigns.current_user, :index, User) do
|
||||
true -> conn
|
||||
_false -> PhilomenaWeb.NotAuthorizedPlug.call(conn)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -30,7 +30,7 @@ defmodule PhilomenaWeb.UnlockController do
|
|||
# Do not log in the user after unlocking to avoid a
|
||||
# leaked token giving the user access to the account.
|
||||
def show(conn, %{"id" => token}) do
|
||||
case Users.unlock_user(token) do
|
||||
case Users.unlock_user_by_token(token) do
|
||||
{:ok, _} ->
|
||||
conn
|
||||
|> put_flash(:info, "Account unlocked successfully. You may now log in.")
|
||||
|
|
|
@ -365,6 +365,7 @@ defmodule PhilomenaWeb.Router do
|
|||
only: [:create, :delete],
|
||||
singleton: true
|
||||
|
||||
resources "/unlock", User.UnlockController, only: [:create], singleton: true
|
||||
resources "/api_key", User.ApiKeyController, only: [:delete], singleton: true
|
||||
resources "/downvotes", User.DownvoteController, only: [:delete], singleton: true
|
||||
resources "/votes", User.VoteController, only: [:delete], singleton: true
|
||||
|
|
|
@ -31,6 +31,18 @@
|
|||
' Two factor auth:
|
||||
strong = enabled_text(@user.otp_required_for_login)
|
||||
|
||||
br
|
||||
|
||||
= if @user.locked_at do
|
||||
i.fas.fa-fw.fa-lock>
|
||||
strong.comment_deleted>
|
||||
' Account locked,
|
||||
=> @user.failed_attempts
|
||||
' failed login attempts
|
||||
- else
|
||||
i.fas.fa-fw.fa-unlock>
|
||||
' Not currently locked
|
||||
|
||||
br
|
||||
|
||||
a.label.label--primary.label--block href="#" data-click-toggle=".js-admin__options__toggle" title="Toggle Controls"
|
||||
|
@ -87,7 +99,7 @@ a.label.label--primary.label--block href="#" data-click-toggle=".js-admin__optio
|
|||
= if @forced do
|
||||
li
|
||||
= link to: Routes.admin_user_force_filter_path(@conn, :delete, @user), data: [confirm: "Are you really, really sure?", method: "delete"] do
|
||||
i.fas.faw-fw.fa-filter
|
||||
i.fas.fa-fw.fa-filter
|
||||
span.admin__button Remove Force Filter
|
||||
|
||||
= if @user.deleted_at do
|
||||
|
@ -101,6 +113,12 @@ a.label.label--primary.label--block href="#" data-click-toggle=".js-admin__optio
|
|||
i.fa.fa-fw.fa-times
|
||||
span.admin__button Deactivate Account
|
||||
|
||||
= if @user.locked_at do
|
||||
li
|
||||
= link to: Routes.admin_user_unlock_path(@conn, :create, @user), data: [method: "post"] do
|
||||
i.fas.fa-fw.fa-unlock
|
||||
span.admin__button Unlock Account
|
||||
|
||||
li
|
||||
= link to: Routes.admin_user_wipe_path(@conn, :create, @user), data: [confirm: "This is irreversible, destroying all identifying information including email. Are you sure?", method: "post"] do
|
||||
i.fas.fa-fw.fa-eraser
|
||||
|
|
|
@ -501,7 +501,7 @@ defmodule Philomena.UsersTest do
|
|||
end
|
||||
end
|
||||
|
||||
describe "unlock_user/2" do
|
||||
describe "unlock_user_by_token/1" do
|
||||
setup do
|
||||
user = locked_user_fixture()
|
||||
|
||||
|
@ -514,26 +514,47 @@ defmodule Philomena.UsersTest do
|
|||
end
|
||||
|
||||
test "unlocks the user with a valid token", %{user: user, token: token} do
|
||||
assert {:ok, unlocked_user} = Users.unlock_user(token)
|
||||
assert {:ok, unlocked_user} = Users.unlock_user_by_token(token)
|
||||
refute unlocked_user.locked_at
|
||||
refute Repo.get!(User, user.id).locked_at
|
||||
refute Repo.get_by(UserToken, user_id: user.id)
|
||||
end
|
||||
|
||||
test "does not confirm with invalid token", %{user: user} do
|
||||
assert Users.unlock_user("oops") == :error
|
||||
assert Users.unlock_user_by_token("oops") == :error
|
||||
assert Repo.get!(User, user.id).locked_at
|
||||
assert Repo.get_by(UserToken, user_id: user.id)
|
||||
end
|
||||
|
||||
test "does not unlocked if token expired", %{user: user, token: token} do
|
||||
{1, nil} = Repo.update_all(UserToken, set: [created_at: ~N[2020-01-01 00:00:00]])
|
||||
assert Users.unlock_user(token) == :error
|
||||
assert Users.unlock_user_by_token(token) == :error
|
||||
assert Repo.get!(User, user.id).locked_at
|
||||
assert Repo.get_by(UserToken, user_id: user.id)
|
||||
end
|
||||
end
|
||||
|
||||
describe "unlock_user/1" do
|
||||
setup do
|
||||
user = user_fixture()
|
||||
locked_user = locked_user_fixture()
|
||||
|
||||
%{user: user, locked_user: locked_user}
|
||||
end
|
||||
|
||||
test "unlocks the user when locked", %{locked_user: locked_user} do
|
||||
assert {:ok, unlocked_user} = Users.unlock_user(locked_user)
|
||||
refute unlocked_user.locked_at
|
||||
refute Repo.get!(User, unlocked_user.id).locked_at
|
||||
end
|
||||
|
||||
test "does nothing when not locked", %{user: user} do
|
||||
assert {:ok, unlocked_user} = Users.unlock_user(user)
|
||||
refute unlocked_user.locked_at
|
||||
refute Repo.get!(User, unlocked_user.id).locked_at
|
||||
end
|
||||
end
|
||||
|
||||
describe "deliver_user_reset_password_instructions/2" do
|
||||
setup do
|
||||
%{user: user_fixture()}
|
||||
|
|
Loading…
Reference in a new issue