diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss index 85423df75..107237a54 100644 --- a/app/assets/stylesheets/admin.scss +++ b/app/assets/stylesheets/admin.scss @@ -199,7 +199,7 @@ body.admin { font-size: rem-calc(12); &:hover, &:active, &:focus { - border: 0; + border-bottom: 1px dotted white; color: #cf2a0e; } } diff --git a/app/assets/stylesheets/layout.scss b/app/assets/stylesheets/layout.scss index 5e7c189bb..e947fcfd9 100644 --- a/app/assets/stylesheets/layout.scss +++ b/app/assets/stylesheets/layout.scss @@ -886,12 +886,6 @@ footer { font-weight: bolder; } } - - form { - .button { - margin-top: rem-calc(24); - } - } } // 08. Forms diff --git a/app/controllers/users/registrations_controller.rb b/app/controllers/users/registrations_controller.rb index 8e04c0d61..a707d7e75 100644 --- a/app/controllers/users/registrations_controller.rb +++ b/app/controllers/users/registrations_controller.rb @@ -10,6 +10,16 @@ class Users::RegistrationsController < Devise::RegistrationsController end end + def delete_form + build_resource({}) + end + + def delete + current_user.erase(erase_params[:erase_reason]) + sign_out + redirect_to root_url, notice: t("devise.registrations.destroyed") + end + def success end @@ -32,6 +42,10 @@ class Users::RegistrationsController < Devise::RegistrationsController params.require(:user).permit(:username, :email, :password, :password_confirmation, :captcha, :captcha_key, :terms_of_service) end + def erase_params + params.require(:user).permit(:erase_reason) + end + def after_inactive_sign_up_path_for(resource_or_scope) users_sign_up_success_path end diff --git a/app/models/user.rb b/app/models/user.rb index f652a8f9c..177befd5c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -23,9 +23,10 @@ class User < ActiveRecord::Base has_many :comments, -> { with_hidden } has_many :failed_census_calls - validates :username, presence: true, unless: :organization? - validates :username, uniqueness: true, unless: :organization? + validates :username, presence: true, if: :username_required? + validates :username, uniqueness: true, if: :username_required? validates :document_number, uniqueness: { scope: :document_type }, allow_nil: true + validate :validate_username_length validates :official_level, inclusion: {in: 0..5} @@ -145,6 +146,21 @@ class User < ActiveRecord::Base Proposal.hide_all proposal_ids end + def erase(erase_reason = nil) + self.hide + self.update( + erase_reason: erase_reason, + username: nil, + email: nil, + unconfirmed_email: nil, + document_number: nil, + phone_number: nil, + encrypted_password: "", + confirmation_token: nil, + reset_password_token: nil, + email_verification_token: nil + ) + end def email_provided? !!(email && email !~ OMNIAUTH_EMAIL_REGEX) || @@ -172,8 +188,15 @@ class User < ActiveRecord::Base super end - private + def username_required? + !organization? && !hidden? + end + def email_required? + !hidden? + end + + private def clean_document_number self.document_number = self.document_number.gsub(/[^a-z0-9]+/i, "").upcase unless self.document_number.blank? end diff --git a/app/views/account/show.html.erb b/app/views/account/show.html.erb index c52219955..40cf43a59 100644 --- a/app/views/account/show.html.erb +++ b/app/views/account/show.html.erb @@ -1,6 +1,10 @@
+ <%= t("devise_views.users.registrations.delete_form.info_reason") %> +
+ + <%= f.text_field :erase_reason, + autofocus: true, + placeholder: t("devise_views.users.registrations.delete_form.erase_reason_label"), + label: t("devise_views.users.registrations.delete_form.erase_reason_label") %> + + <%= f.submit t("devise_views.users.registrations.delete_form.submit"), class: "button radius alert expand" %> +<% end %> diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index da441e691..ff1b5c179 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -96,6 +96,7 @@ ignore_missing: - 'unauthorized.*' - 'errors.messages.blank' - 'errors.messages.taken' + - 'devise.registrations.destroyed' ## Consider these keys used: ignore_unused: diff --git a/config/locales/devise_views.en.yml b/config/locales/devise_views.en.yml index 2c04d3ce8..2c7ef86bb 100644 --- a/config/locales/devise_views.en.yml +++ b/config/locales/devise_views.en.yml @@ -77,6 +77,12 @@ en: instructions_1_html: "Please review your email inbox - we have sent you a link to confirm your account." instructions_2_html: "Once you click that link, you will be able to start participating" back_to_index: "Understood, take me back to the home page" + delete_form: + title: "Erase account" + info: "This action can not be undone. Please make sure this is what you want." + info_reason: "If you want, leave us a reason (optional)" + erase_reason_label: "Reason" + submit: "Erase my account" organizations: registrations: new: diff --git a/config/locales/devise_views.es.yml b/config/locales/devise_views.es.yml index f2ca13215..42576b6ff 100644 --- a/config/locales/devise_views.es.yml +++ b/config/locales/devise_views.es.yml @@ -77,6 +77,12 @@ es: instructions_1_html: "Por favor revisa tu correo electrónico - te hemos enviado un enlace para confirmar tu cuenta." instructions_2_html: "Una vez confirmado, podrás empezar a participar." back_to_index: "Entendido, volver a la página principal" + delete_form: + title: "Darme de baja" + info: "Esta acción no se puede deshacer. Una vez que des de baja tu cuenta, no podrás volver a hacer login con ella." + info_reason: "Si quieres, escribe el motivo por el que te das de baja (opcional)." + erase_reason_label: "Razón de la baja" + submit: "Borrar mi cuenta" organizations: registrations: new: diff --git a/config/locales/en.yml b/config/locales/en.yml index 8e56cd69e..db56b3e4f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -282,6 +282,7 @@ en: change_credentials_link: "Change my credentials" email_on_comment_label: "Receive email when someone comments on my debates or proposals" email_on_comment_reply_label: "Receive email when someone replies to my comments" + erase_account_link: "Erase my account" personal: "Personal data" username_label: "Username" phone_number_label: "Phone number" diff --git a/config/locales/es.yml b/config/locales/es.yml index 18763a895..e05ed35e9 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -282,6 +282,7 @@ es: change_credentials_link: "Cambiar mis datos de acceso" email_on_comment_label: "Recibir un email cuando alguien comenta en mis propuestas o debates" email_on_comment_reply_label: "Recibir un email cuando alguien contesta a mis comentarios" + erase_account_link: "Darme de baja" personal: "Datos personales" username_label: "Nombre de usuario" phone_number_label: "Teléfono" diff --git a/config/routes.rb b/config/routes.rb index c1a0e38ba..5e6f07c2c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,9 +1,5 @@ Rails.application.routes.draw do - as :user do - match '/user/confirmation' => 'users/confirmations#update', :via => :patch, :as => :update_user_confirmation - end - devise_for :users, controllers: { registrations: 'users/registrations', sessions: 'users/sessions', @@ -22,7 +18,11 @@ Rails.application.routes.draw do end devise_scope :user do + patch '/user/confirmation', to: 'users/confirmations#update', as: :update_user_confirmation + get 'users/sign_up/success', to: 'users/registrations#success' + get 'users/registrations/delete_form', to: 'users/registrations#delete_form' + delete 'users/registrations', to: 'users/registrations#delete' get :finish_signup, to: 'users/registrations#finish_signup' patch :do_finish_signup, to: 'users/registrations#do_finish_signup' end @@ -60,7 +60,9 @@ Rails.application.routes.draw do end end - resource :account, controller: "account", only: [:show, :update] + resource :account, controller: "account", only: [:show, :update, :delete] do + collection { get :erase } + end resource :verification, controller: "verification", only: [:show] scope module: :verification do diff --git a/db/migrate/20151016110703_add_erase_reason_to_users.rb b/db/migrate/20151016110703_add_erase_reason_to_users.rb new file mode 100644 index 000000000..be88869b5 --- /dev/null +++ b/db/migrate/20151016110703_add_erase_reason_to_users.rb @@ -0,0 +1,5 @@ +class AddEraseReasonToUsers < ActiveRecord::Migration + def change + add_column :users, :erase_reason, :string + end +end diff --git a/db/migrate/20151019133719_remove_user_constraints.rb b/db/migrate/20151019133719_remove_user_constraints.rb new file mode 100644 index 000000000..0f59a3d34 --- /dev/null +++ b/db/migrate/20151019133719_remove_user_constraints.rb @@ -0,0 +1,5 @@ +class RemoveUserConstraints < ActiveRecord::Migration + def change + change_column(:users, :email, :string, null: true, unique: true) + end +end diff --git a/db/schema.rb b/db/schema.rb index 56d5a4a9f..29fda8e68 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20151015135154) do +ActiveRecord::Schema.define(version: 20151019133719) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -257,7 +257,7 @@ ActiveRecord::Schema.define(version: 20151015135154) do add_index "tags", ["proposals_count"], name: "index_tags_on_proposals_count", using: :btree create_table "users", force: :cascade do |t| - t.string "email", default: "", null: false + t.string "email", default: "" t.string "encrypted_password", default: "", null: false t.string "reset_password_token" t.datetime "reset_password_sent_at" @@ -294,6 +294,7 @@ ActiveRecord::Schema.define(version: 20151015135154) do t.string "letter_verification_code" t.integer "failed_census_calls_count", default: 0 t.datetime "level_two_verified_at" + t.string "erase_reason" end add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree diff --git a/spec/features/account_spec.rb b/spec/features/account_spec.rb index e0249072c..029864ec9 100644 --- a/spec/features/account_spec.rb +++ b/spec/features/account_spec.rb @@ -81,4 +81,20 @@ feature 'Account' do expect(page).to have_content error_message end + + scenario 'Erasing account' do + visit account_path + + click_link 'Erase my account' + + fill_in 'user_erase_reason', with: 'a test' + + click_button 'Erase my account' + + expect(page).to have_content "Your account has been successfully cancelled" + + login_through_form_as(@user) + + expect(page).to have_content "Invalid email or password" + end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 14f20ad1d..2e92ced35 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -302,4 +302,36 @@ describe User do end + describe "#erase" do + it "anonymizes a user and marks him as hidden" do + user = create(:user, + username: "manolo", + unconfirmed_email: "a@a.com", + document_number: "1234", + phone_number: "5678", + encrypted_password: "foobar", + confirmation_token: "token1", + reset_password_token: "token2", + email_verification_token: "token3") + user.erase('a test') + user.reload + + expect(user.erase_reason).to eq('a test') + expect(user.hidden_at).to be + + expect(user.username).to be_nil + + expect(user.email).to be_nil + expect(user.unconfirmed_email).to be_nil + expect(user.document_number).to be_nil + expect(user.phone_number).to be_nil + + expect(user.encrypted_password).to be_empty + + expect(user.confirmation_token).to be_nil + expect(user.reset_password_token).to be_nil + expect(user.email_verification_token).to be_nil + end + end + end