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

Feature - Allow users to be deleted #1592

Open
wants to merge 10 commits into
base: master
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
10 changes: 10 additions & 0 deletions .github/workflows/test_and_deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,18 @@ jobs:
run: bundle install
- name: Load schema
run: bundle exec rake db:schema:load
- name: Setup hosts
run: |
echo '

127.0.0.1 test.localmumuki.io
' | sudo tee -a /etc/hosts
- name: Setup Xvfb
run: Xvfb :99 &
- name: Run tests
run: bundle exec rake
env:
DISPLAY: :99

test-firefox:
env:
Expand Down
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ gem 'puma'
gem 'execjs'
gem 'therubyracer', platforms: :ruby
gem 'uglifier', '~> 2.7'
gem 'mumuki-domain', github: 'mumuki/mumuki-domain', branch: 'feature-delete-user-account'

group :test do
gem 'rspec-rails', '~> 3.6'
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,17 @@ o.reindex_usages!

Now you will be able to visit that guide at `http://localhost:3000/central/guides/#{slug}`

## Debugging email sender

The development environment is configured to "send" emails via `mailcatcher`, a mock server, if it is available. Run these commands to install and run it - and do it _before_ the emails are sent, so it can actually _catch_ them:

```bash
gem install mailcatcher
mailcatcher
```

Once up and running, go to http://localhost:1080/ to see which emails have been sent. Unfortunately, the developers recommend not to install it via Bundler, so it has to be done this way. :woman_shrugging:

## JavaScript API Docs

In order to be customized by runners, Laboratory exposes the following selectors and methods
Expand Down
21 changes: 21 additions & 0 deletions app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,27 @@ def unsubscribe
redirect_to root_path, notice: t(:unsubscribed_successfully)
end

def delete_request
end

def send_delete_confirmation_email
current_user.generate_delete_account_token!
UserMailer.delete_account(current_user).deliver_now
redirect_to delete_request_user_path
end

def delete_confirmation
redirect_to delete_confirmation_invalid_user_path unless @user.delete_account_token_matches? params[:token]
end

def delete_confirmation_invalid
end

def disable
current_user.disable!
redirect_to root_path
end

def permissible_params
super << [:avatar_id, :avatar_type]
end
Expand Down
11 changes: 11 additions & 0 deletions app/helpers/mailer_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module MailerHelper
def delete_account_url_for(user)
delete_confirmation_user_url host: organic_domain_for(user), token: user.delete_account_token
end

private

def organic_domain_for(user)
Mumukit::Platform.laboratory.organic_domain(user.last_organization)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer to explicitly obtain organization from where the user clicked delete profile button

end
end
1 change: 1 addition & 0 deletions app/mailers/application_mailer.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
class ApplicationMailer < ActionMailer::Base
default from: Rails.configuration.reminder_sender_email
add_template_helper MailerHelper
layout 'mailer'

def self.mailer_environment_variables
Expand Down
6 changes: 6 additions & 0 deletions app/mailers/user_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ def no_submissions_reminder(user)
end
end

def delete_account(user)
with_locale(user) do
build_email t(:delete_account_mumuki), 'delete_account'
end
end

def certificate(certificate)
with_locale certificate.user, certificate.organization do
attachments[certificate.filename] = pdf_for(certificate)
Expand Down
4 changes: 2 additions & 2 deletions app/views/layouts/_organization_chooser.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="modal fade mu-organization-chooser" id="redirect" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal fade mu-organization-chooser" id="organization-chooser-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
Expand All @@ -14,7 +14,7 @@
</div>
</div>
<script>
$("#redirect").modal({
$("#organization-chooser-modal").modal({
backdrop: 'static',
keyboard: false
});
Expand Down
6 changes: 6 additions & 0 deletions app/views/user_mailer/delete_account.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<%= delete_account_url_for @user %>

© Copyright 2015-<%= DateTime.now.year %> Mumuki.

<%= t :stop_emails? %>
<%= t :cancel_subscription %>
19 changes: 19 additions & 0 deletions app/views/users/_user_delete_account.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<div>
<h3 class="text-danger"><%= t :delete_account %></h3>
<div class="row">
<div class="col-md-8">
<p><%= t :delete_account_explain %></p>
</div>
<div class="col-md-4">
<div class="pull-right">
<button type="button" class="btn btn-danger" data-toggle="modal" data-target="#user-delete-account-modal">
<%= t :delete_account %>
</button>
</div>
</div>
</div>
</div>

<%= content_for :no_container do %>
<%= render partial: 'user_delete_modal', locals: { submit_url: delete_request_user_path } %>
<% end %>
17 changes: 17 additions & 0 deletions app/views/users/_user_delete_confirmation.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<%= content_for :breadcrumbs do %>
<%= breadcrumbs @user %>
<% end %>

<div class="row">
<div class="mu-inline-block-left">
<h1>
<%= t :delete_account %>
</h1>
</div>
</div>

<div class="row">
<div class="col-md-12">
<%= t :delete_account_confirmation_email_explain_html, user_email: @user.email, support_email: Rails.configuration.reminder_sender_email %>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not for you to address it @faloi, but we should define another configuration for Mumuki general purpose email

</div>
</div>
44 changes: 44 additions & 0 deletions app/views/users/_user_delete_modal.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<script type="text/javascript" charset="utf-8">
function checkConfirmationText() {
const val = $('#confirm-delete-input').val();
$('#delete-account-button').prop('disabled', val !== '<%= t :delete_account_confirmation_text %>');
}
</script>

<div class="modal fade" id="user-delete-account-modal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><%= t :delete_account %></h4>
</div>
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<%= t :delete_account_modal_explain_html, name: @user.name %>
</div>
<div class="row">
<% @user.student_granted_organizations.each do |organization| %>
<div class="col-md-4 text-center">
<%= image_tag(organization.banner_url, width: '100%', class: 'pull-left') %>
<p><%= organization.name %></p>
</div>
<% end %>
</div>
<div class="row">
<%= t :delete_account_confirmation_request %> <i><%= t :delete_account_confirmation_text %></i>.
</div>
<div class="row">
<%= form_with url: submit_url do |f| %>
<div class="form-group">
<input class="form-control" type="text" id="confirm-delete-input" autocomplete="off" onkeyup="checkConfirmationText()">
</div>
<%= f.submit t(:delete_account_agree), class: 'btn btn-danger', id: 'delete-account-button', disabled: true %>
<% end %>
</div>
</div>
</div>
</div>
</div>
</div>
2 changes: 2 additions & 0 deletions app/views/users/_user_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
<div>
<span> <strong><%= t :programming_since %>:</strong> <%= t(:time_since, time: time_ago_in_words(@user.created_at)) %> </span>
</div>
<hr>
<%= render partial: 'user_delete_account' %>
</div>
</div>
<div class="mu-profile-actions mobile visible-xs">
Expand Down
11 changes: 11 additions & 0 deletions app/views/users/delete_confirmation.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
$('#user-delete-account-modal').modal();
});
</script>

<%= render partial: 'user_delete_confirmation' %>

<%= content_for :no_container do %>
<%= render partial: 'user_delete_modal', locals: { submit_url: delete_confirmation_user_url } %>
<% end %>
22 changes: 22 additions & 0 deletions app/views/users/delete_confirmation_invalid.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<%= content_for :breadcrumbs do %>
<%= breadcrumbs @user %>
<% end %>

<div class="row">
<div class="mu-inline-block-left">
<h1>
<%= t :delete_account %>
</h1>
</div>
</div>

<div class="row">
<div class="col-md-12">
<p>
<%= t :delete_account_invalid_token %>
</p>
<p>
<%= t :delete_account_try_again_html, profile_url: user_path %>
</p>
</div>
</div>
5 changes: 5 additions & 0 deletions app/views/users/delete_request.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<%= render partial: 'user_delete_confirmation' %>

<%= content_for :no_container do %>
<%= render partial: 'user_delete_modal', locals: { submit_url: delete_request_user_url } %>
<% end %>
5 changes: 5 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@
get :messages
get :discussions
get :certificates
get :delete_request
post :delete_request, to: 'users#send_delete_confirmation_email'
get :delete_confirmation_invalid
get :delete_confirmation
post :delete_confirmation, to: 'users#disable'
end

resources :faqs, only: [:index]
Expand Down
10 changes: 10 additions & 0 deletions lib/mumuki/laboratory/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@ en:
create_submission: Submit
created_at: Created at
date: Date
delete_account: Delete account
delete_account_agree: I understand the consequences and want to delete my account
delete_account_confirmation_email_explain_html: <p>We sent you an email to <a href="%{user_email}">%{user_email}</a> to continue with the removal process.
delete_account_confirmation_request: To confirm this action, please write
delete_account_confirmation_text: delete my account
delete_account_explain: After deleting your account, you will lose access to all the contents and to your progress.
delete_account_invalid_token: We are sorry, the link has expired or is invalid.
delete_account_modal_explain_html: <p>You're about to delete <strong>%{name}</strong> account</p><p>By doing that, you will lose access to the following paths:</p>
delete_account_mumuki: Delete your Mumuki account
delete_account_try_again_html: If you still want to delete your account, begin the process again from <a href="&{profile_url}">your profile</a>.
description: Description
destroy: Destroy
destroy_message: delete the message
Expand Down
12 changes: 12 additions & 0 deletions lib/mumuki/laboratory/locales/es-CL.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ es-CL:
date: Fecha
day: Día
days: Días
delete_account: Eliminar cuenta
delete_account_agree: Comprendo las consecuencias y quiero eliminar mi cuenta
delete_account_confirmation_email_explain_html: <p>Te enviamos un correo electrónico a <a href="%{user_email}">%{user_email}</a> para continuar con el proceso de eliminación. </p>
delete_account_confirmation_request: Para confirmar esta acción, escribí
delete_account_confirmation_text: quiero eliminar mi cuenta
<p>Si no lo recibiste, por favor escribinos a <a href="%{support_email}">%{support_email}</a>.</p>
delete_account_explain: Al eliminar tu cuenta, perderás acceso a todos los contenidos, así como a tu progreso.
delete_account_invalid_token: Lo sentimos, el enlace que te trajo hasta aquí ha expirado o es inválido.
delete_account_modal_explain_html: <p>Estás a punto de eliminar la cuenta de <strong>%{name}</strong></p>
<p>Al hacerlo, perderás acceso a los siguientes recorridos:</p>
delete_account_mumuki: Eliminar tu cuenta de Mumuki
delete_account_try_again_html: Si todavía quieres eliminar tu cuenta, volvé a iniciar el proceso desde <a href="{profile_url}">tu perfil</a>.
description: Descripción
destroy_message: eliminar el mensaje
destroy: Eliminar
Expand Down
10 changes: 10 additions & 0 deletions lib/mumuki/laboratory/locales/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ es:
date: Fecha
day: Día
days: Días
delete_account: Eliminar cuenta
delete_account_agree: Comprendo las consecuencias y quiero eliminar mi cuenta
delete_account_confirmation_email_explain_html: <p>Te enviamos un correo electrónico a <a href="%{user_email}">%{user_email}</a> para continuar con el proceso de eliminación. </p><p>Si no lo recibiste, por favor escribinos a <a href="%{support_email}">%{support_email}</a>.</p>
delete_account_confirmation_request: Para confirmar esta acción, escribí
delete_account_confirmation_text: quiero eliminar mi cuenta
delete_account_explain: Al eliminar tu cuenta, perderás acceso a todos los contenidos, así como a tu progreso.
delete_account_invalid_token: Lo sentimos, el enlace que te trajo hasta aquí ha expirado o es inválido.
delete_account_modal_explain_html: <p>Estás a punto de eliminar la cuenta de <strong>%{name}</strong></p><p>Al hacerlo, perderás acceso a los siguientes recorridos:</p>
delete_account_mumuki: Eliminar tu cuenta de Mumuki
delete_account_try_again_html: Si todavía querés eliminar tu cuenta, volvé a iniciar el proceso desde <a href="&{profile_url}">tu perfil</a>.
description: Descripción
destroy_message: eliminar el mensaje
destroy: Eliminar
Expand Down
5 changes: 5 additions & 0 deletions lib/mumuki/laboratory/locales/pt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ pt:
date: Data
day: Dia
days: Dias
delete_account: Deletar conta
delete_account_agree:
delete_account_confirmation_email_explain_html:
delete_account_explain:
delete_account_modal_explain_html:
description: Descrição
destroy_message: excluir a mensagem
destroy: Excluir
Expand Down
20 changes: 10 additions & 10 deletions spec/capybara_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,11 @@ def selected_driver
:selenium_headless
when 'safari'
:selenium_safari
else
:rack_test
end
end

def run_with_selenium?
selected_driver.to_s.start_with? 'selenium'
selected_driver
end

def register_safari_driver!
Expand Down Expand Up @@ -96,20 +94,22 @@ def exclude_selenium_failing_tests!
end
end

# Configuration

register_safari_driver! if selected_driver == :selenium_safari
Capybara.default_driver = selected_driver

# If no driver is selected, it will use RackTest (fastest) except for tests that explicitly require JS support.
# See https://github.com/teamcapybara/capybara#using-capybara-with-rspec for more details about this behavior.
Capybara.default_driver = selected_driver || :rack_test
Capybara.javascript_driver = selected_driver || :selenium_headless

# Include port on the URL, so we don't need to forward it via nginx or so.
Capybara.always_include_port = true

# TODO: fix the tests that depend on hidden elements and remove this
Capybara.ignore_hidden_elements = false

if run_with_selenium?
register_request_headers_workaround!
exclude_selenium_failing_tests!

# Include port on the URL, so we don't need to forward it via nginx or so
Capybara.always_include_port = true
end

puts "Running Capybara tests with #{selected_driver}, #{Capybara.ignore_hidden_elements ? '' : 'not '}ignoring hidden elements"
puts "Running Capybara tests with #{Capybara.default_driver}, #{Capybara.ignore_hidden_elements ? '' : 'not '}ignoring hidden elements"
Loading