From e8fa5481d1abb0e7567091383305696949fa041f Mon Sep 17 00:00:00 2001 From: Nicolas Zermati Date: Mon, 31 May 2021 08:26:56 +0200 Subject: [PATCH] Clean-up controllers that were used for anonymizing the user --- app/controllers/matches/users_controller.rb | 36 ------------- app/controllers/redirects_controller.rb | 36 +++++++++++++ .../slot_alerts/users_controller.rb | 33 ------------ .../match_confirmation_instructions.mjml | 5 +- app/views/matches/users/edit.html.erb | 16 ------ app/views/slot_alert_mailer/follow_up.mjml | 3 +- app/views/slot_alert_mailer/notify.mjml | 3 +- app/views/slot_alerts/users/edit.html.erb | 1 - .../users/_confirm_destroy_message.html.erb | 41 +++++++++----- config/routes.rb | 9 +--- config/routes/redirects.rb | 3 +- spec/requests/redirections_spec.rb | 53 +++++++++++++++++++ 12 files changed, 127 insertions(+), 112 deletions(-) delete mode 100644 app/controllers/matches/users_controller.rb create mode 100644 app/controllers/redirects_controller.rb delete mode 100644 app/controllers/slot_alerts/users_controller.rb delete mode 100644 app/views/matches/users/edit.html.erb delete mode 100644 app/views/slot_alerts/users/edit.html.erb create mode 100644 spec/requests/redirections_spec.rb diff --git a/app/controllers/matches/users_controller.rb b/app/controllers/matches/users_controller.rb deleted file mode 100644 index dcfe6c49d..000000000 --- a/app/controllers/matches/users_controller.rb +++ /dev/null @@ -1,36 +0,0 @@ -module Matches - class UsersController < ApplicationController - before_action :set_match, only: [:edit] - rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized - - def pundit_user - @match.user - end - - def edit - end - - private - - def set_match - @match = Match.find_by(match_confirmation_token: params[:match_confirmation_token]) - - if @match.blank? - flash[:error] = "Désolé, ce lien d’invitation n’est pas valide." - return redirect_to root_path - elsif @match.user.blank? - flash[:error] = "Désolé, ce lien d’invitation n’est plus valide. L’utilisateur a été supprimé." - return redirect_to root_path - end - authorize @match - end - - def user_not_authorized(exception) - policy_name = exception - .policy.class.to_s.underscore - message = exception.message || (t "#{policy_name}.#{exception.query}", scope: "pundit", default: :default) - flash[:error] = message - redirect_back(fallback_location: root_path) - end - end -end diff --git a/app/controllers/redirects_controller.rb b/app/controllers/redirects_controller.rb new file mode 100644 index 000000000..bfcb2cc47 --- /dev/null +++ b/app/controllers/redirects_controller.rb @@ -0,0 +1,36 @@ +# This controller holds temporary redirection logic. +# After a while, it would be fine removing each action as it shouldn't be used anymore. +class RedirectsController < ApplicationController + rescue_from ActiveRecord::RecordNotFound, with: :redirect_to_root_with_message + rescue_from ArgumentError, with: :redirect_to_root_with_message + + def confirm_destroy_from_match + redirect_to confirm_destroy_path( + Match.find_by!(match_confirmation_token: params[:match_confirmation_token]).user + ) + end + + def confirm_destroy_from_slot_alert + redirect_to confirm_destroy_path( + SlotAlert.find_by!(token: params[:token]).user + ) + end + + private + + def skip_pundit? + true + end + + def redirect_to_root_with_message + flash[:error] = "Désolé, ce lien n’est plus valide." + redirect_to root_path + end + + def confirm_destroy_path(user) + raise ArgumentError if user.anonymized_at + + token = user.signed_id(purpose: "users.destroy", expires_in: 1.minute) + confirm_destroy_profile_path(authentication_token: token) + end +end diff --git a/app/controllers/slot_alerts/users_controller.rb b/app/controllers/slot_alerts/users_controller.rb deleted file mode 100644 index 733d6bb39..000000000 --- a/app/controllers/slot_alerts/users_controller.rb +++ /dev/null @@ -1,33 +0,0 @@ -module SlotAlerts - class UsersController < ApplicationController - before_action :set_alert, only: [:edit] - rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized - - def pundit_user - @alert.user - end - - def edit - end - - private - - def set_alert - @alert = SlotAlert.find_by(token: params[:token]) - - if @alert.user.blank? - flash[:error] = "Désolé, ce lien n’est plus valide." - return redirect_to root_path - end - authorize @alert - end - - def user_not_authorized(exception) - policy_name = exception - .policy.class.to_s.underscore - message = exception.message || (t "#{policy_name}.#{exception.query}", scope: "pundit", default: :default) - flash[:error] = message - redirect_back(fallback_location: root_path) - end - end -end diff --git a/app/views/match_mailer/match_confirmation_instructions.mjml b/app/views/match_mailer/match_confirmation_instructions.mjml index 570db5480..2c4780b68 100644 --- a/app/views/match_mailer/match_confirmation_instructions.mjml +++ b/app/views/match_mailer/match_confirmation_instructions.mjml @@ -1,3 +1,4 @@ +<% authentication_token = @match.user.signed_id(purpose: "users.destroy", expires_in: 7.days) %> @@ -16,13 +17,13 @@ Vous ne souhaitez plus être informé de doses disponibles ? - + Supprimer mon compte Si le lien ne fonctionne pas, copiez et collez l’adresse suivante dans votre navigateur :
- <%= edit_matches_users_url(match_confirmation_token: @match_confirmation_token) %> + <%= confirm_destroy_profile_url(authentication_token: authentication_token) %>
<%= render partial: "mailer/social_networks", formats: [:html] %>
diff --git a/app/views/matches/users/edit.html.erb b/app/views/matches/users/edit.html.erb deleted file mode 100644 index 8506c9cc1..000000000 --- a/app/views/matches/users/edit.html.erb +++ /dev/null @@ -1,16 +0,0 @@ -<% if @match.confirmed? %> -
-
-

- Vous avez confirmé votre rendez-vous. -

-

- Vous ne pouvez pas supprimer vos informations actuellement car vous avez confirmé un rendez-vous de vaccination. -
- Votre profil sera anonymisé quelques jours après le RDV. -

-
-
-<% else %> - <%= render partial: "users/confirm_destroy_message", locals: { user: @match.user } %> -<% end %> diff --git a/app/views/slot_alert_mailer/follow_up.mjml b/app/views/slot_alert_mailer/follow_up.mjml index 25138f53c..e61f058ce 100644 --- a/app/views/slot_alert_mailer/follow_up.mjml +++ b/app/views/slot_alert_mailer/follow_up.mjml @@ -1,3 +1,4 @@ +<% authentication_token = @alert.user.signed_id(purpose: "users.destroy", expires_in: 7.days) %> @@ -9,7 +10,7 @@
Si c'est le cas nous vous invitons à supprimer votre compte Covidliste.
- + Supprimer mon compte diff --git a/app/views/slot_alert_mailer/notify.mjml b/app/views/slot_alert_mailer/notify.mjml index 36105ab45..99a51853c 100644 --- a/app/views/slot_alert_mailer/notify.mjml +++ b/app/views/slot_alert_mailer/notify.mjml @@ -1,4 +1,5 @@ <%- distance = distance_delta({lat: @alert.user.lat, lon: @alert.user.lon}, {lat: @slot.latitude, lon: @slot.longitude}) %> +<% authentication_token = @alert.user.signed_id(purpose: "users.destroy", expires_in: 7.days) %> @@ -48,7 +49,7 @@ Vous ne souhaitez plus être informé de doses ou de créneaux disponibles ?
- <%= link_to "Supprimer mon compte", edit_slot_alerts_users_url(token: @alert_token) %> + <%= link_to "Supprimer mon compte", confirm_destroy_profile_url(authentication_token: authentication_token) %>
diff --git a/app/views/slot_alerts/users/edit.html.erb b/app/views/slot_alerts/users/edit.html.erb deleted file mode 100644 index f00afd837..000000000 --- a/app/views/slot_alerts/users/edit.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= render partial: "users/confirm_destroy_message", locals: { user: @alert.user } %> diff --git a/app/views/users/_confirm_destroy_message.html.erb b/app/views/users/_confirm_destroy_message.html.erb index cffe793b5..91659bb69 100644 --- a/app/views/users/_confirm_destroy_message.html.erb +++ b/app/views/users/_confirm_destroy_message.html.erb @@ -1,14 +1,29 @@ -
-
-

- Vous souhaitez vous désinscrire de Covidliste en supprimant votre compte ? -

- <% token = user.signed_id(purpose: "users.destroy", expires_in: 1.hour) %> - <%= button_to "Supprimer mon compte", profile_path(authentication_token: token), - method: :delete, - id: dom_id(user, :delete), - class: "btn btn-outline-danger btn-lg mt-4", - data: { - confirm: "En confirmant, votre compte ainsi que toutes les données associées seront supprimées de nos serveurs. Êtes-vous sûr(e) ?"} %> +<% if user.matches.confirmed.any? %> +
+
+

+ Vous avez confirmé votre rendez-vous. +

+

+ Vous ne pouvez pas supprimer vos informations actuellement car vous avez confirmé un rendez-vous de vaccination. +
+ Votre profil sera anonymisé quelques jours après le RDV. +

+
-
+<% else %> +
+
+

+ Vous souhaitez vous désinscrire de Covidliste en supprimant votre compte ? +

+ <% token = user.signed_id(purpose: "users.destroy", expires_in: 1.hour) %> + <%= button_to "Supprimer mon compte", profile_path(authentication_token: token), + method: :delete, + id: dom_id(user, :delete), + class: "btn btn-outline-danger btn-lg mt-4", + data: { + confirm: "En confirmant, votre compte ainsi que toutes les données associées seront supprimées de nos serveurs. Êtes-vous sûr(e) ?"} %> +
+
+<% end %> diff --git a/config/routes.rb b/config/routes.rb index 62be0a10d..3362daca5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -120,18 +120,11 @@ resources :partner_external_accounts, only: [:destroy] end - ## matches - namespace :matches do - resource :users, only: [:edit] - end - # slot alerts get "/s/:token" => "slot_alerts#show", :as => :slot_alert patch "/s/:token" => "slot_alerts#update" - namespace :slot_alerts do - resource :users, only: [:edit] - end + # Matches get "/m/:match_confirmation_token(/:source)" => "matches#show", :as => :match patch "/m/:match_confirmation_token(/:source)" => "matches#update" delete "/m/:match_confirmation_token(/:source)" => "matches#destroy" diff --git a/config/routes/redirects.rb b/config/routes/redirects.rb index 782333b8b..4bc124c56 100644 --- a/config/routes/redirects.rb +++ b/config/routes/redirects.rb @@ -1,8 +1,9 @@ # Handle old routes redirections (before devise users path migration) - get "/login", to: redirect("/users/login", status: 302), as: :legacy_new_user_session post "/login", to: redirect("/users/login", status: 302), as: :legacy_user_session delete "/logout", to: redirect("/users/logout", status: 302), as: :legacy_destroy_user_session get "/profile", to: redirect("/users/profile", status: 302), as: :legacy_profile get "/confirmation/new", to: redirect("/users/confirmation/new", status: 302), as: :legacy_new_user_confirmation get "/confirmation", to: redirect { |_, request| "/users/confirmation#{request.params.present? ? "?" + request.params.to_query : ""}" }, as: :legacy_user_confirmation +get "/matches/users/edit", controller: :redirects, action: :confirm_destroy_from_match, as: :legacy_edit_matches_users +get "/slot_alerts/users/edit", controller: :redirects, action: :confirm_destroy_from_slot_alert, as: :legacy_edit_slot_alerts_users diff --git a/spec/requests/redirections_spec.rb b/spec/requests/redirections_spec.rb new file mode 100644 index 000000000..6899f19fe --- /dev/null +++ b/spec/requests/redirections_spec.rb @@ -0,0 +1,53 @@ +require "rails_helper" + +RSpec.describe "Redirects", type: :request do + describe "From a matches email to delete the account" do + it "redirects to the confirm_destroy_profile_path" do + match = create(:match) + + get legacy_edit_matches_users_path(match_confirmation_token: match.match_confirmation_token) + expect(response).to redirect_to(%r{#{confirm_destroy_profile_path}}) + + auth_token = Rack::Utils.parse_query(URI.parse(response.location).query).fetch("authentication_token") + expect(User.find_signed(auth_token, purpose: "users.destroy")).to eq(match.user) + end + + it "redirects to the root_path when the token is wrong" do + match = create(:match) + get legacy_edit_matches_users_path(match_confirmation_token: match.match_confirmation_token + "foo") + expect(response).to redirect_to(root_path) + end + + it "redirects to the root_path when the user is anynomized" do + match = create(:match) + match.user.anonymize! + get legacy_edit_matches_users_path(match_confirmation_token: match.match_confirmation_token) + expect(response).to redirect_to(root_path) + end + end + + describe "From a slot alert email to delete the account" do + it "redirects to the confirm_destroy_profile_path" do + slot_alert = create(:slot_alert) + + get legacy_edit_slot_alerts_users_path(token: slot_alert.token) + expect(response).to redirect_to(%r{#{confirm_destroy_profile_path}}) + + auth_token = Rack::Utils.parse_query(URI.parse(response.location).query).fetch("authentication_token") + expect(User.find_signed(auth_token, purpose: "users.destroy")).to eq(slot_alert.user) + end + + it "redirects to the root_path when the token is wrong" do + slot_alert = create(:slot_alert) + get legacy_edit_slot_alerts_users_path(token: slot_alert.token + "foo") + expect(response).to redirect_to(root_path) + end + + it "redirects to the root_path when the user is anynomized" do + slot_alert = create(:slot_alert) + slot_alert.user.anonymize! + get legacy_edit_slot_alerts_users_path(token: slot_alert.token) + expect(response).to redirect_to(root_path) + end + end +end