Skip to content

Commit 7b07d49

Browse files
authored
Merge pull request #481 from testmycode/destroying-user
Add the possibility for user to delete their account
2 parents c148a3d + a4c6cc7 commit 7b07d49

13 files changed

+252
-4
lines changed

app/controllers/application_controller.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,15 @@ class ApplicationController < ActionController::Base
2121
include BreadcrumbHelpers
2222
include EmbeddableHelper
2323
include AuthorizeCollectionHelper
24+
include ApplicationHelper
2425
check_authorization
2526

2627
rescue_from CanCan::AccessDenied do |_exception|
27-
respond_access_denied
28+
if current_user.guest?
29+
redirect_to(login_path(return_to: return_to_link))
30+
else
31+
respond_access_denied
32+
end
2833
end
2934

3035
rescue_from ActiveRecord::RecordNotFound do |exception|

app/controllers/users_controller.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,44 @@ def send_verification_email
9292
redirect_to root_path, notice: "Verification email sent to #{user.email}."
9393
end
9494

95+
def verify_destroying_user
96+
@user = authenticate_current_user_destroy
97+
token = VerificationToken.delete_user.find_by!(user: @user, token: params[:id])
98+
end
99+
100+
def destroy_user
101+
im_sure = params[:im_sure]
102+
if im_sure != "1"
103+
redirect_to verify_destroying_user_url, notice: "Please check the checkbox after you have read the instructions."
104+
return
105+
end
106+
user = authenticate_current_user_destroy
107+
user_authentication = User.authenticate(user.login, params[:user][:password])
108+
if user_authentication.nil?
109+
redirect_to verify_destroying_user_url, { alert: "The password was incorrect." }
110+
return
111+
end
112+
token = VerificationToken.delete_user.find_by!(user: user, token: params[:id])
113+
username = user.login
114+
sign_out if current_user == user
115+
user.destroy
116+
redirect_to root_url, notice: "The account #{username} has been permanently destroyed."
117+
end
118+
119+
def send_destroy_email
120+
user = authenticate_current_user_destroy
121+
UserMailer.destroy_confirmation(user).deliver_now
122+
redirect_to root_path, notice: "Verification email sent to #{user.email}."
123+
end
124+
95125
private
96126

127+
def authenticate_current_user_destroy
128+
user = User.find(params[:user_id])
129+
authorize! :destroy, user
130+
user
131+
end
132+
97133
def set_email
98134
user_params = params[:user]
99135

app/mailers/user_mailer.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ def email_confirmation(user)
66
mail(from: SiteSetting.value('emails')['from'], to: user.email, subject: "Confirm your TestMyCode Account email address")
77
end
88

9+
def destroy_confirmation(user)
10+
@user = user
11+
token = user.verification_tokens.delete_user.create!
12+
@url = base_url + verify_destroying_user_path(@user.id, token.token)
13+
mail(from: SiteSetting.value('emails')['from'], to: user.email, subject: "Confirm deleting your TestMyCode account")
14+
end
15+
916

1017
private
1118

app/models/ability.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ def initialize(user)
3737
end
3838

3939
can :create, User if SiteSetting.value(:enable_signup)
40+
cannot :destroy, User
41+
can :destroy, User do |u|
42+
u == user
43+
end
4044

4145
cannot :read, Course
4246
can :read, Course do |c|

app/models/verification_token.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ class VerificationToken < ActiveRecord::Base
44

55
belongs_to :user
66

7-
enum type: [:email]
7+
enum type: [:email, :delete_user]
88

99
validates :type, presence: true
1010
validates :user, presence: true
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5+
</head>
6+
<body>
7+
<p>Hello!</p>
8+
9+
<p>You have requested deleting your TestMyCode account "<%= @user.login %>".</p>
10+
11+
<p>Please proceed to the following link to continue the deletion process.</p>
12+
13+
<a href="<%= @url %>"><%= @url %></a>
14+
15+
<p>If you didn't request deleting your account, just ignore this message.</p>
16+
</body>
17+
</html>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Hello!
2+
3+
You have requested deleting your TestMyCode account "<%= @user.login %>".
4+
5+
Please proceed to the following link to continue the deletion process.
6+
7+
<%= @url %>
8+
9+
If you didn't request deleting your account, just ignore this message.

app/views/users/show.html.erb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@
33
<h1><%= @user.login %></h1>
44

55
<%= render :partial => 'users/form', :user => @user %>
6+
7+
<% if can? :destroy, @user %>
8+
<%= button_to 'Request deleting account', send_destroy_email_path(@user.id), method: :post, class: 'btn btn-danger' %>
9+
<% end %>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<h1>Deleting the account <%= @user.login %></h1>
2+
3+
<div class="jumbotron hero-unit-alert alert-danger">
4+
Deleting your account will have the following consequences:
5+
<ul>
6+
<li>You will lose all your acquired exercise points. We will not be able to recover them.</li>
7+
<li>You will not be able to receive a grade from any course that uses TestMyCode.</li>
8+
<li>We will not be able to verify the authenticity of any certificates that you have generated.</li>
9+
<ul>
10+
</div>
11+
12+
13+
<%= form_tag(destroy_user_path, method: :delete, class: 'form-horizontal') do %>
14+
<div class="form-group">
15+
<%= check_box_tag :im_sure %>
16+
<%= label_tag "I've read the above and I'm sure I understand the consequences", nil, class: "control-label", for: :im_sure %>
17+
</div>
18+
<div class="form-group">
19+
<%= bs_labeled_field("Your password", password_field(:user, :password, :autocomplete => 'off', class: 'form-control')) %>
20+
</div>
21+
<p><strong>Pressing the button below will permanently destroy your TestMyCode account.</strong></p>
22+
<%= submit_tag("Destroy my account permanently", class: "btn btn-danger", data: { confirm: "Are you sure you want to delete the account #{@user.login}?"}, disabled: "disabled", id: :destroy_button) %>
23+
<% end %>
24+
25+
26+
<script>
27+
var checkBox = document.getElementById('im_sure')
28+
var destroyButton = document.getElementById('destroy_button')
29+
checkBox.addEventListener("click", function() {
30+
destroyButton.disabled = !checkBox.checked
31+
})
32+
</script>

bin/spec_integration

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
#!/bin/sh
22

3-
RSPEC_PATTERN="spec/integration/**/*.rb"
3+
RSPEC_PATTERN="spec/integration/destroying_user_spec.rb"
44
bundle exec rake spec SPEC_OPTS="--pattern $RSPEC_PATTERN --format documentation"

0 commit comments

Comments
 (0)