move account deletion out of a tranaction and into a job
This commit is contained in:
parent
7204ef8e26
commit
686464c36e
9 changed files with 152 additions and 74 deletions
|
|
@ -71,7 +71,8 @@ class UsersController < ApplicationController
|
|||
end
|
||||
|
||||
def destroy
|
||||
current_user.destroy
|
||||
Resque.enqueue(Job::DeleteAccount, current_user.id)
|
||||
current_user.lock_access!
|
||||
sign_out current_user
|
||||
flash[:notice] = I18n.t 'users.destroy'
|
||||
redirect_to root_path
|
||||
|
|
|
|||
15
app/models/jobs/delete_account.rb
Normal file
15
app/models/jobs/delete_account.rb
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# Copyright (c) 2010, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
|
||||
module Job
|
||||
class DeleteAccount < Base
|
||||
@queue = :delete_account
|
||||
def self.perform_delegate(user_id)
|
||||
user = User.find(user_id)
|
||||
user.remove_all_traces
|
||||
user.destroy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -13,7 +13,8 @@ class User < ActiveRecord::Base
|
|||
|
||||
devise :invitable, :database_authenticatable, :registerable,
|
||||
:recoverable, :rememberable, :trackable, :validatable,
|
||||
:timeoutable, :token_authenticatable
|
||||
:timeoutable, :token_authenticatable, :lockable,
|
||||
:lock_strategy => :none, :unlock_strategy => :none
|
||||
|
||||
before_validation :strip_and_downcase_username
|
||||
before_validation :set_current_language, :on => :create
|
||||
|
|
@ -39,11 +40,11 @@ class User < ActiveRecord::Base
|
|||
has_many :services
|
||||
has_many :user_preferences
|
||||
|
||||
before_destroy :disconnect_everyone, :remove_mentions, :remove_person
|
||||
before_save do
|
||||
person.save if person && person.changed?
|
||||
end
|
||||
|
||||
|
||||
attr_accessible :getting_started, :password, :password_confirmation, :language, :disable_mail
|
||||
|
||||
def update_user_preferences(pref_hash)
|
||||
|
|
@ -317,7 +318,11 @@ class User < ActiveRecord::Base
|
|||
AppConfig[:admins].present? && AppConfig[:admins].include?(self.username)
|
||||
end
|
||||
|
||||
protected
|
||||
def remove_all_traces
|
||||
disconnect_everyone
|
||||
remove_mentions
|
||||
remove_person
|
||||
end
|
||||
|
||||
def remove_person
|
||||
self.person.destroy
|
||||
|
|
@ -325,11 +330,11 @@ class User < ActiveRecord::Base
|
|||
|
||||
def disconnect_everyone
|
||||
self.contacts.each do |contact|
|
||||
unless contact.person.owner.nil?
|
||||
if contact.person.remote?
|
||||
self.disconnect(contact)
|
||||
else
|
||||
contact.person.owner.disconnected_by(self.person)
|
||||
remove_contact(contact, :force => true)
|
||||
else
|
||||
self.disconnect(contact)
|
||||
end
|
||||
end
|
||||
self.aspects.destroy_all
|
||||
|
|
|
|||
|
|
@ -704,7 +704,7 @@ en:
|
|||
private_message: "...you receive a private message?"
|
||||
liked: "...someone likes your post?"
|
||||
change: "Change"
|
||||
destroy: "Account successfully closed."
|
||||
destroy: "Your account has been locked. It may take 20 minutes for us to finish closing your account. Thank you for trying Diaspora."
|
||||
getting_started:
|
||||
welcome: "Welcome to Diaspora!"
|
||||
signup_steps: "Finish your sign up by completing these three steps:"
|
||||
|
|
|
|||
9
db/migrate/20110603181015_lockable_users.rb
Normal file
9
db/migrate/20110603181015_lockable_users.rb
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
class LockableUsers < ActiveRecord::Migration
|
||||
def self.up
|
||||
add_column :users, :locked_at, :datetime
|
||||
end
|
||||
|
||||
def self.down
|
||||
remove_column :users, :locked_at
|
||||
end
|
||||
end
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20110527135552) do
|
||||
ActiveRecord::Schema.define(:version => 20110603181015) do
|
||||
|
||||
create_table "aspect_memberships", :force => true do |t|
|
||||
t.integer "aspect_id", :null => false
|
||||
|
|
@ -369,6 +369,7 @@ ActiveRecord::Schema.define(:version => 20110527135552) do
|
|||
t.integer "invited_by_id"
|
||||
t.string "invited_by_type"
|
||||
t.string "authentication_token", :limit => 30
|
||||
t.datetime "locked_at"
|
||||
end
|
||||
|
||||
add_index "users", ["authentication_token"], :name => "index_users_on_authentication_token", :unique => true
|
||||
|
|
|
|||
|
|
@ -145,4 +145,15 @@ describe UsersController do
|
|||
response.should redirect_to new_user_session_path
|
||||
end
|
||||
end
|
||||
|
||||
describe '#destroy' do
|
||||
it 'enqueues a delete job' do
|
||||
Resque.should_receive(:enqueue).with(Job::DeleteAccount, alice.id)
|
||||
delete :destroy
|
||||
end
|
||||
it 'locks the user out' do
|
||||
delete :destroy
|
||||
alice.reload.access_locked?.should be_true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
30
spec/models/jobs/delete_account_spec.rb
Normal file
30
spec/models/jobs/delete_account_spec.rb
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Copyright (c) 2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Job::DeleteAccount do
|
||||
describe '#perform' do
|
||||
it 'calls remove_all_traces' do
|
||||
stub_find_for(bob)
|
||||
bob.should_receive(:remove_all_traces)
|
||||
Job::DeleteAccount.perform(bob.id)
|
||||
end
|
||||
|
||||
it 'calls destroy' do
|
||||
stub_find_for(bob)
|
||||
bob.should_receive(:destroy)
|
||||
Job::DeleteAccount.perform(bob.id)
|
||||
end
|
||||
def stub_find_for model
|
||||
model.class.stub!(:find) do |id, conditions|
|
||||
if id == model.id
|
||||
model
|
||||
else
|
||||
model.class.find_by_id(id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -226,7 +226,7 @@ describe User do
|
|||
it "returns false if the users are already connected" do
|
||||
alice.can_add?(bob.person).should be_false
|
||||
end
|
||||
|
||||
|
||||
it "returns false if the user has already sent a request to that person" do
|
||||
alice.share_with(eve.person, alice.aspects.first)
|
||||
alice.reload
|
||||
|
|
@ -374,71 +374,68 @@ describe User do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'account removal' do
|
||||
it 'should disconnect everyone' do
|
||||
alice.should_receive(:disconnect_everyone)
|
||||
alice.destroy
|
||||
describe 'account deletion' do
|
||||
describe '#remove_all_traces' do
|
||||
it 'should disconnect everyone' do
|
||||
alice.should_receive(:disconnect_everyone)
|
||||
alice.remove_all_traces
|
||||
end
|
||||
|
||||
|
||||
it 'should remove mentions' do
|
||||
alice.should_receive(:remove_mentions)
|
||||
alice.remove_all_traces
|
||||
end
|
||||
|
||||
it 'should remove person' do
|
||||
alice.should_receive(:remove_person)
|
||||
alice.remove_all_traces
|
||||
end
|
||||
|
||||
it 'should remove all aspects' do
|
||||
lambda {
|
||||
alice.remove_all_traces
|
||||
}.should change{ alice.aspects(true).count }.by(-1)
|
||||
end
|
||||
end
|
||||
|
||||
it 'removes invitations from the user' do
|
||||
alice.invite_user alice.aspects.first.id, 'email', 'blah@blah.blah'
|
||||
lambda {
|
||||
alice.destroy
|
||||
}.should change {alice.invitations_from_me(true).count }.by(-1)
|
||||
end
|
||||
describe '#destroy' do
|
||||
it 'removes invitations from the user' do
|
||||
alice.invite_user alice.aspects.first.id, 'email', 'blah@blah.blah'
|
||||
lambda {
|
||||
alice.destroy
|
||||
}.should change {alice.invitations_from_me(true).count }.by(-1)
|
||||
end
|
||||
|
||||
it 'removes invitations to the user' do
|
||||
Invitation.create(:sender_id => eve.id, :recipient_id => alice.id, :aspect_id => eve.aspects.first.id)
|
||||
lambda {
|
||||
alice.destroy
|
||||
}.should change {alice.invitations_to_me(true).count }.by(-1)
|
||||
end
|
||||
it 'removes invitations to the user' do
|
||||
Invitation.create(:sender_id => eve.id, :recipient_id => alice.id, :aspect_id => eve.aspects.first.id)
|
||||
lambda {
|
||||
alice.destroy
|
||||
}.should change {alice.invitations_to_me(true).count }.by(-1)
|
||||
end
|
||||
|
||||
it 'should remove mentions' do
|
||||
alice.should_receive(:remove_mentions)
|
||||
alice.destroy
|
||||
end
|
||||
|
||||
it 'should remove person' do
|
||||
alice.should_receive(:remove_person)
|
||||
alice.destroy
|
||||
end
|
||||
|
||||
it 'should remove all aspects' do
|
||||
lambda {
|
||||
alice.destroy
|
||||
}.should change{ alice.aspects(true).count }.by(-1)
|
||||
end
|
||||
|
||||
it 'removes all contacts' do
|
||||
lambda {
|
||||
alice.destroy
|
||||
}.should change {
|
||||
alice.contacts.count
|
||||
}.by(-1)
|
||||
end
|
||||
|
||||
it 'removes all service connections' do
|
||||
Services::Facebook.create(:access_token => 'what', :user_id => alice.id)
|
||||
lambda {
|
||||
alice.destroy
|
||||
}.should change {
|
||||
alice.services.count
|
||||
}.by(-1)
|
||||
it 'removes all service connections' do
|
||||
Services::Facebook.create(:access_token => 'what', :user_id => alice.id)
|
||||
lambda {
|
||||
alice.destroy
|
||||
}.should change {
|
||||
alice.services.count
|
||||
}.by(-1)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#remove_person' do
|
||||
it 'should remove the person object' do
|
||||
person = alice.person
|
||||
alice.destroy
|
||||
alice.remove_person
|
||||
person.reload
|
||||
person.should be nil
|
||||
person.should be_nil
|
||||
end
|
||||
|
||||
it 'should remove the posts' do
|
||||
message = alice.post(:status_message, :text => "hi", :to => alice.aspects.first.id)
|
||||
alice.reload
|
||||
alice.destroy
|
||||
alice.remove_person
|
||||
proc { message.reload }.should raise_error ActiveRecord::RecordNotFound
|
||||
end
|
||||
end
|
||||
|
|
@ -449,41 +446,50 @@ describe User do
|
|||
sm = Factory(:status_message)
|
||||
mention = Mention.create(:person => person, :post=> sm)
|
||||
alice.reload
|
||||
alice.destroy
|
||||
alice.remove_mentions
|
||||
proc { mention.reload }.should raise_error ActiveRecord::RecordNotFound
|
||||
end
|
||||
end
|
||||
|
||||
describe '#disconnect_everyone' do
|
||||
it 'has no error on a local friend who has deleted his account' do
|
||||
alice.destroy
|
||||
Job::DeleteAccount.perform(alice.id)
|
||||
lambda {
|
||||
bob.destroy
|
||||
bob.disconnect_everyone
|
||||
}.should_not raise_error
|
||||
end
|
||||
|
||||
it 'has no error when the user has sent local requests' do
|
||||
alice.share_with(eve.person, alice.aspects.first)
|
||||
lambda {
|
||||
alice.destroy
|
||||
alice.disconnect_everyone
|
||||
}.should_not raise_error
|
||||
end
|
||||
|
||||
it 'should send retractions to remote poeple' do
|
||||
it 'sends retractions to remote poeple' do
|
||||
person = eve.person
|
||||
eve.delete
|
||||
person.owner_id = nil
|
||||
person.save
|
||||
alice.contacts.create(:person => person, :aspects => [alice.aspects.first])
|
||||
|
||||
alice.should_receive(:disconnect).once
|
||||
alice.destroy
|
||||
alice.disconnect_everyone
|
||||
end
|
||||
|
||||
it 'should disconnect local people' do
|
||||
it 'disconnects local people' do
|
||||
lambda {
|
||||
alice.destroy
|
||||
alice.remove_all_traces
|
||||
}.should change{bob.reload.contacts.count}.by(-1)
|
||||
end
|
||||
|
||||
it 'removes all contacts' do
|
||||
lambda {
|
||||
alice.disconnect_everyone
|
||||
}.should change {
|
||||
alice.contacts.count
|
||||
}.by(-1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -519,7 +525,7 @@ describe User do
|
|||
|
||||
describe "#add_contact_to_aspect" do
|
||||
it 'adds the contact to the aspect' do
|
||||
lambda {
|
||||
lambda {
|
||||
alice.add_contact_to_aspect(@contact, @aspect1)
|
||||
}.should change(@aspect1.contacts, :count).by(1)
|
||||
end
|
||||
|
|
@ -557,7 +563,7 @@ describe User do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
context 'likes' do
|
||||
before do
|
||||
@message = alice.post(:status_message, :text => "cool", :to => alice.aspects.first)
|
||||
|
|
@ -565,24 +571,24 @@ describe User do
|
|||
@like = alice.like(true, :post => @message)
|
||||
@dislike = bob.like(false, :post => @message)
|
||||
end
|
||||
|
||||
|
||||
describe '#like_for' do
|
||||
it 'returns the correct like' do
|
||||
alice.like_for(@message).should == @like
|
||||
bob.like_for(@message).should == @dislike
|
||||
end
|
||||
|
||||
|
||||
it "returns nil if there's no like" do
|
||||
alice.like_for(@message2).should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe '#liked?' do
|
||||
it "returns true if there's a like" do
|
||||
alice.liked?(@message).should be_true
|
||||
bob.liked?(@message).should be_true
|
||||
end
|
||||
|
||||
|
||||
it "returns false if there's no like" do
|
||||
alice.liked?(@message2).should be_false
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in a new issue