Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#5052] Allow users to request account closure #7874

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions app/controllers/admin_user_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,15 @@ def modify_comment_visibility
redirect_back(fallback_location: admin_users_url)
end

def account_closure_requests
@title = 'Account closure requests'

# Find requests where the account associated with the request is not closed
@account_closure_requests = AccountClosureRequest.
joins(:user).
where(users: { closed_at: nil })
end

private

def user_params
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/admin_users_account_closing_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def create
'Something went wrong. The user account could not be closed.'
end

redirect_to admin_user_path(@closed_user)
redirect_back_or_to admin_user_path(@closed_user)
end

private
Expand Down
3 changes: 3 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ class RouteNotFound < StandardError
# Standard headers, footers and navigation for whole site
layout "default"

# Defaults are :alert and :notice, but Alaveteli uses :error as well
add_flash_types :error

include FastGettext::Translation # make functions like _, n_, N_ etc available)
include AlaveteliPro::PostRedirectHandler

Expand Down
46 changes: 46 additions & 0 deletions app/controllers/users/close_account_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Handles the process of a user requesting to close their account.
class Users::CloseAccountController < ApplicationController
before_action :authenticate_user!

def new
# Display a form that explains the process to the users
end

def create
# If they haven't checked the "confirm" checkbox, redirect back to the form
if params[:confirm] == "0"
return redirect_to users_close_account_path,
error: "You must confirm that you want to close your account"
end

# Otherwise, create a record of the user's request to close their account
current_user.create_account_closure_request!

# Send the user an acknowledgement email
UserMailer.account_closure_requested(current_user).deliver_now

# TODO: Should the user be logged out here?

redirect_to root_path,
notice: "Your account closure request has been received. " \
"We will be in touch."
end

private

def authenticate_user!
return if authenticated?

ask_to_login(
web: _('To close your account on {{site_name}}', site_name: site_name),
email: _(
'Then you can close your account on {{site_name}}',
site_name: site_name
),
email_subject: _(
'Close your account on {{site_name}}',
site_name: site_name
)
)
end
end
10 changes: 10 additions & 0 deletions app/mailers/user_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,14 @@
to: new_email,
subject: _("Unable to change email address on {{site_name}}", site_name: site_name))
end

def account_closure_requested(user)
@name = user.name

set_reply_to_headers(user)
mail_user(
user,
_("Your account closure request on {{site_name}}",site_name: site_name)

Check warning on line 55 in app/mailers/user_mailer.rb

View workflow job for this annotation

GitHub Actions / build

[rubocop] reported by reviewdog 🐶 Space missing after comma. (https://rubystyle.guide#spaces-operators) Raw Output: app/mailers/user_mailer.rb:55:56: C: Layout/SpaceAfterComma: Space missing after comma. (https://rubystyle.guide#spaces-operators)
)
end
end
13 changes: 13 additions & 0 deletions app/models/account_closure_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# == Schema Information
# Schema version: 20230718062820
#
# Table name: account_closure_requests
#
# id :bigint not null, primary key
# user_id :bigint not null
# created_at :datetime not null
# updated_at :datetime not null
#
class AccountClosureRequest < ApplicationRecord
belongs_to :user
end
2 changes: 1 addition & 1 deletion app/models/outgoing_message.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# == Schema Information
# Schema version: 20230412084830
# Schema version: 20230718062820
#
# Table name: outgoing_messages
#
Expand Down
4 changes: 4 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ class User < ApplicationRecord
inverse_of: :user,
dependent: :destroy

has_one :account_closure_request,
inverse_of: :user,
dependent: :destroy

scope :active, -> { not_banned.not_closed }
scope :banned, -> { where.not(ban_text: '') }
scope :not_banned, -> { where(ban_text: '') }
Expand Down
1 change: 1 addition & 0 deletions app/views/admin_general/_admin_navbar.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
<ul class="dropdown-menu" role="menu">
<li><%= link_to 'Users', admin_users_path %></li>
<li><%= link_to 'Tracks', admin_tracks_path %></li>
<li><%= link_to 'Account closure requests', account_closure_requests_admin_users_path %></li>
</ul>
</li>

Expand Down
9 changes: 9 additions & 0 deletions app/views/admin_user/_close_account_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<%= form_tag admin_users_account_closing_index_path(user_id: user.id), class: 'span3 form form-inline' do %>
<% disabled = user.closed? %>
<% submit_class = %w(btn btn-danger) %>
<% submit_class << 'disabled' if disabled %>
<%= submit_tag 'Close',
class: submit_class,
disabled: disabled,
data: { confirm: 'Are you sure? This is irreversible.' } %>
<% end %>
4 changes: 4 additions & 0 deletions app/views/admin_user/_scopes.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
<%= nav_li(admin_sign_ins_path) do %>
<%= link_to 'Sign Ins', admin_sign_ins_path %>
<% end %>

<%= nav_li(account_closure_requests_admin_users_path) do %>
<%= link_to 'Account closure requests', account_closure_requests_admin_users_path %>
<% end %>
</ul>
</div>
</div>
35 changes: 35 additions & 0 deletions app/views/admin_user/account_closure_requests.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<%= render 'scopes' %>

<div class="row">
<div class="span12">
<% if @account_closure_requests.any? %>
<table class="table table-striped">
<thead>
<tr>
<th>Request ID</th>
<th>User</th>
<th>Created at</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<% @account_closure_requests.each do |request| %>
<tr id="account-closure-request-<%= request.id %>">
<td><%= request.id %></td>
<td>
<%= link_to request.user.name, admin_user_path(request.user) %>
</td>
<td><%= request.created_at.to_fs(:long) %></td>
<td>
<%= render 'close_account_form', { user: request.user } %>
</td>
</tr>
<% end %>
</tbody>
</table>

<% else %>
<p>No users have requested to close their accounts.</p>
<% end %>
</div>
</div>
10 changes: 1 addition & 9 deletions app/views/admin_user/edit.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,7 @@
<br/>
</div>
<hr>
<%= form_tag admin_users_account_closing_index_path(user_id: @admin_user.id), class: 'span3 form form-inline' do %>
<% disabled = @admin_user.closed? %>
<% submit_class = %w(btn btn-danger) %>
<% submit_class << 'disabled' if disabled %>
<%= submit_tag 'Close',
class: submit_class,
disabled: disabled,
data: { confirm: 'Are you sure? This is irreversible.' } %>
<% end %>
<%= render 'close_account_form', { user: @admin_user } %>
</div>

<div class="danger-zone__item">
Expand Down
3 changes: 2 additions & 1 deletion app/views/user/_show_user_info.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
<%= link_to _('Change profile photo'), set_profile_photo_path %> |
<% end %>
<%= link_to _('Change your password'), new_password_change_path %> |
<%= link_to _('Change your email'), signchangeemail_path %>
<%= link_to _('Change your email'), signchangeemail_path %> |
<%= link_to _('Close your account'), users_close_account_path %>
<% if AlaveteliConfiguration.enable_two_factor_auth %>
|
<% if @display_user.otp_enabled? %>
Expand Down
7 changes: 7 additions & 0 deletions app/views/user_mailer/account_closure_requested.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<%= raw @name %>,

<%= _("You've requested to close your account on {{site_name}}." \
'We will process your request and will be in touch once it has been actioned.',
:site_name => site_name.html_safe) %>

-- <%= _('the {{site_name}} team', :site_name => site_name.html_safe) %>
26 changes: 26 additions & 0 deletions app/views/users/close_account/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<% @title = "Close your account" %>
<h1><%= @title %></h1>

<p>If you no longer wish to use your WhatDoTheyKnow account, you can ask us to close your account.</p>

<p>Closing your account will:</p>

<ul>
<li>Set your user name to &#91;Name Removed&#93;</li>
<li>Reset your email address to something random</li>
<li>Clear your about me text</li>
<li>Disable all email alerts</li>
<li>Hide any requests you have made from your profile page</li>
<li>Make an automatic attempt to remove your name from your requests</li>
</ul>

<p>Closing your account will prevent you from logging in. If you have any requests that are ongoing, you will not be able to send any follow up messages to public authorities.</p>

<%= form_with url: users_close_account_path, method: :post do |form| %>
<p>
<%= form.check_box :confirm, class: "checkbox" %>
I understand that closing my account will mean that I <b>will not</b> be able to login or follow up on my requests, and that this cannot be undone.
</p>

<%= form.submit "Close my account", class: "button alert", data: { confirm: "Are you sure you want to close your account?" } %>
<% end %>
4 changes: 4 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,9 @@ def matches?(request)
get 'email_alerts/disable/:token',
to: 'email_alerts#destroy',
as: :disable_email_alerts

get 'close_account', to: 'close_account#new', as: :close_account
post 'close_account', to: 'close_account#create'
end

namespace :users, path: 'profile' do
Expand Down Expand Up @@ -710,6 +713,7 @@ def matches?(request)
get 'active', :on => :collection
get 'banned', :on => :collection
get 'closed', :on => :collection
get 'account_closure_requests', :on => :collection
get 'show_bounce_message', :on => :member
post 'clear_bounce', :on => :member
post 'clear_profile_photo', :on => :member
Expand Down
8 changes: 8 additions & 0 deletions db/migrate/20230718062820_create_account_closure_requests.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class CreateAccountClosureRequests < ActiveRecord::Migration[7.0]
def change
create_table :account_closure_requests do |t|
t.references :user, null: false, foreign_key: true
t.timestamps
end
end
end
21 changes: 21 additions & 0 deletions spec/controllers/admin_user_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -449,4 +449,25 @@
}.to change(ActsAsXapian::ActsAsXapianJob, :count).by(1)
end
end

describe "GET #account_closure_requests" do
it "assigns @account_closure_requests with open account" do
user_with_closed_account = FactoryBot.create(:user, closed_at: Time.now)
user_with_open_account = FactoryBot.create(:user)
request_for_closed_account = FactoryBot.create(
:account_closure_request,
user: user_with_closed_account
)
request_for_open_account = FactoryBot.create(
:account_closure_request,
user: user_with_open_account
)

get :account_closure_requests

expect(
assigns(:account_closure_requests)
).to eq([request_for_open_account])
end
end
end
46 changes: 46 additions & 0 deletions spec/controllers/users/close_account_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# spec/controllers/users/close_account_controller_spec.rb
require 'spec_helper'

RSpec.describe Users::CloseAccountController, type: :controller do
describe "POST #create" do
let(:user) { FactoryBot.create(:user) }

before do
sign_in user
end

after do
user.account_closure_request&.destroy
end

it "shows the user a confirmation page" do
get :new
assert_response :success
expect(response).to render_template(:new)
end

it "asks the user to check the confirmation checkbox" do
post :create, params: { confirm: "0" }
assert_response :redirect
expect(response).to redirect_to(users_close_account_path)
expect(flash[:error]).to eq("You must confirm that you want to close your account")

Check warning on line 26 in spec/controllers/users/close_account_controller_spec.rb

View workflow job for this annotation

GitHub Actions / build

[rubocop] reported by reviewdog 🐶 Line is too long. [89/80] (https://rubystyle.guide#max-line-length) Raw Output: spec/controllers/users/close_account_controller_spec.rb:26:81: C: Layout/LineLength: Line is too long. [89/80] (https://rubystyle.guide#max-line-length)
end

it "creates a record of the user's request to close their account" do
post :create, params: { confirm: "1" }

user.reload
expect(user.account_closure_request).to be_present

# Check email has been sent
expect(ActionMailer::Base.deliveries.count).to eq(1)
email = ActionMailer::Base.deliveries.last
expect(email.to).to eq([user.email])
expect(email.subject).to eq("Your account closure request on #{site_name}")

Check warning on line 39 in spec/controllers/users/close_account_controller_spec.rb

View workflow job for this annotation

GitHub Actions / build

[rubocop] reported by reviewdog 🐶 Line is too long. [81/80] (https://rubystyle.guide#max-line-length) Raw Output: spec/controllers/users/close_account_controller_spec.rb:39:81: C: Layout/LineLength: Line is too long. [81/80] (https://rubystyle.guide#max-line-length)

assert_response :redirect
expect(response).to redirect_to(root_path)
expect(flash[:notice]).to eq("Your account closure request has been received. We will be in touch.")

Check warning on line 43 in spec/controllers/users/close_account_controller_spec.rb

View workflow job for this annotation

GitHub Actions / build

[rubocop] reported by reviewdog 🐶 Line is too long. [106/80] (https://rubystyle.guide#max-line-length) Raw Output: spec/controllers/users/close_account_controller_spec.rb:43:81: C: Layout/LineLength: Line is too long. [106/80] (https://rubystyle.guide#max-line-length)
end
end
end
14 changes: 14 additions & 0 deletions spec/factories/account_closure_requests.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# == Schema Information
# Schema version: 20230718062820
#
# Table name: account_closure_requests
#
# id :bigint not null, primary key
# user_id :bigint not null
# created_at :datetime not null
# updated_at :datetime not null
#
FactoryBot.define do
factory :account_closure_request do
end
end
Loading
Loading