change close account to clear profile, still need to dispatch account deletion xml

This commit is contained in:
Ilya Zhitomirskiy 2011-11-10 10:57:48 -08:00 committed by Maxwell Salzberg
parent 7667029e71
commit 0bd101dca9
16 changed files with 204 additions and 55 deletions

View file

@ -82,7 +82,7 @@ class UsersController < ApplicationController
def destroy def destroy
if params[:user] && params[:user][:current_password] && current_user.valid_password?(params[:user][:current_password]) if params[:user] && params[:user][:current_password] && current_user.valid_password?(params[:user][:current_password])
Resque.enqueue(Jobs::DeleteAccount, current_user.id) Resque.enqueue(Jobs::DeleteAccount, current_user.id)
current_user.lock_access! current_user.close_account!
sign_out current_user sign_out current_user
flash[:notice] = I18n.t 'users.destroy.success' flash[:notice] = I18n.t 'users.destroy.success'
redirect_to multi_path redirect_to multi_path

View file

@ -17,8 +17,8 @@ class AccountDeleter
attr_accessor :person, :user attr_accessor :person, :user
def initialize(diaspora_id) def initialize(diaspora_handle)
self.person = Person.where(:diaspora_handle => diaspora_id).first self.person = Person.where(:diaspora_handle => diaspora_handle).first
self.user = self.person.owner self.user = self.person.owner
end end
@ -90,11 +90,12 @@ class AccountDeleter
end end
def tombstone_person_and_profile def tombstone_person_and_profile
self.person.close_account! self.person.lock_access!
self.person.clear_profile!
end end
def tombstone_user def tombstone_user
self.user.close_account! self.user.clear_account!
end end
def delete_contacts_of_me def delete_contacts_of_me

View file

@ -3,5 +3,44 @@
# the COPYRIGHT file. # the COPYRIGHT file.
class AccountDeletion < ActiveRecord::Base class AccountDeletion < ActiveRecord::Base
include ROXML
include Diaspora::Webhooks
belongs_to :person
after_create :queue_delete_account
attr_accessible :person
xml_attr :diaspora_handle
def person=(person)
self[:diaspora_handle] = person.diaspora_handle
self[:person_id] = person.id
end
def diaspora_handle=(diaspora_handle)
self[:diaspora_handle] = diaspora_handle
self[:person_id] ||= Person.find_by_diaspora_handle(diaspora_handle).id
end
def queue_delete_account
Resque.enqueue(Jobs::DeleteAccount, self.id)
end
def perform!
AccountDeleter.new(self.diaspora_handle).perform!
self.dispatch if person.local?
end
def subscribers(user)
person.owner.contact_people | Person.who_have_reshared_a_users_posts(person.owner)
end
def dispatch
Postzord::Dispatcher.build(person.owner, self).post
end
end end

View file

@ -6,9 +6,9 @@
module Jobs module Jobs
class DeleteAccount < Base class DeleteAccount < Base
@queue = :delete_account @queue = :delete_account
def self.perform(user_id) def self.perform(account_deletion_id)
user = User.find(user_id) account_deletion = AccountDeletion.find(account_deletion_id)
AccountDeleter.new(user.person.diaspora_handle).perform! account_deletion.perform!
end end
end end
end end

View file

@ -61,6 +61,10 @@ class Person < ActiveRecord::Base
scope :profile_tagged_with, lambda{|tag_name| joins(:profile => :tags).where(:profile => {:tags => {:name => tag_name}}).where('profiles.searchable IS TRUE') } scope :profile_tagged_with, lambda{|tag_name| joins(:profile => :tags).where(:profile => {:tags => {:name => tag_name}}).where('profiles.searchable IS TRUE') }
scope :who_have_reshared_a_users_posts, lambda{|user|
joins(:posts).where(:posts => {:root_guid => StatusMessage.guids_for_author(user.person), :type => 'Reshare'} )
}
def self.community_spotlight def self.community_spotlight
AppConfig[:community_spotlight].present? ? Person.where(:diaspora_handle => AppConfig[:community_spotlight]) : [] AppConfig[:community_spotlight].present? ? Person.where(:diaspora_handle => AppConfig[:community_spotlight]) : []
end end
@ -285,10 +289,13 @@ class Person < ActiveRecord::Base
self.update_attributes(:url => newuri) self.update_attributes(:url => newuri)
end end
def close_account! def lock_access!
self.profile.tombstone!
self.closed_account = true self.closed_account = true
self.save self.save
end
def clear_profile!
self.profile.tombstone!
self self
end end

View file

@ -42,6 +42,10 @@ class StatusMessage < Post
joins(:likes).where(:likes => {:author_id => person.id}) joins(:likes).where(:likes => {:author_id => person.id})
} }
def self.guids_for_author(person)
Post.connection.select_values(Post.where(:author_id => person.id).select('posts.guid').to_sql)
end
def self.user_tag_stream(user, tag_ids) def self.user_tag_stream(user, tag_ids)
owned_or_visible_by_user(user). owned_or_visible_by_user(user).
tag_stream(tag_ids) tag_stream(tag_ids)

View file

@ -490,6 +490,12 @@ class User < ActiveRecord::Base
end end
def close_account! def close_account!
AccountDeletion.create(:person => self.person)
self.person.lock_access!
self.lock_access!
end
def clear_account!
clearable_fields.each do |field| clearable_fields.each do |field|
self[field] = nil self[field] = nil
end end
@ -502,6 +508,6 @@ class User < ActiveRecord::Base
private private
def clearable_fields def clearable_fields
self.attributes.keys - ["id", "username", "encrypted_password", "created_at", "updated_at"] self.attributes.keys - ["id", "username", "encrypted_password", "created_at", "updated_at", "locked_at"]
end end
end end

View file

@ -1,7 +1,7 @@
class CreateAccountDeletions < ActiveRecord::Migration class CreateAccountDeletions < ActiveRecord::Migration
def self.up def self.up
create_table :account_deletions do |t| create_table :account_deletions do |t|
t.string :diaspora_id t.string :diaspora_handle
t.integer :person_id t.integer :person_id
end end
end end

View file

@ -12,8 +12,8 @@
ActiveRecord::Schema.define(:version => 20111109023618) do ActiveRecord::Schema.define(:version => 20111109023618) do
create_table "account_deletion", :force => true do |t| create_table "account_deletions", :force => true do |t|
t.string "diaspora_id" t.string "diaspora_handle"
t.integer "person_id" t.integer "person_id"
end end

View file

@ -10,6 +10,7 @@ describe UsersController do
@aspect = @user.aspects.first @aspect = @user.aspects.first
@aspect1 = @user.aspects.create(:name => "super!!") @aspect1 = @user.aspects.create(:name => "super!!")
sign_in :user, @user sign_in :user, @user
@controller.stub(:current_user).and_return(@user)
end end
describe '#export' do describe '#export' do
@ -192,15 +193,16 @@ describe UsersController do
delete :destroy, :user => { :current_password => "stuff" } delete :destroy, :user => { :current_password => "stuff" }
end end
it 'closes the account' do
alice.should_receive(:close_account!)
delete :destroy, :user => { :current_password => "bluepin7" }
end
it 'enqueues a delete job' do it 'enqueues a delete job' do
Resque.should_receive(:enqueue).with(Jobs::DeleteAccount, alice.id) Resque.should_receive(:enqueue).with(Jobs::DeleteAccount, alice.id)
delete :destroy, :user => { :current_password => "bluepin7" } delete :destroy, :user => { :current_password => "bluepin7" }
end end
it 'locks the user out' do
delete :destroy, :user => { :current_password => "bluepin7" }
alice.reload.access_locked?.should be_true
end
end end
describe '#confirm_email' do describe '#confirm_email' do

View file

@ -123,8 +123,13 @@ describe AccountDeleter do
end end
describe '#tombstone_person_and_profile' do describe '#tombstone_person_and_profile' do
it 'calls close_account! on person' do it 'calls clear_profile! on person' do
@account_deletion.person.should_receive(:close_account!) @account_deletion.person.should_receive(:clear_profile!)
@account_deletion.tombstone_person_and_profile
end
it 'calls lock_access! on person' do
@account_deletion.person.should_receive(:lock_access!)
@account_deletion.tombstone_person_and_profile @account_deletion.tombstone_person_and_profile
end end
end end
@ -160,7 +165,7 @@ describe AccountDeleter do
describe "#tombstone_user" do describe "#tombstone_user" do
it 'calls strip_model on user' do it 'calls strip_model on user' do
bob.should_receive(:close_account!) bob.should_receive(:clear_account!)
@account_deletion.tombstone_user @account_deletion.tombstone_user
end end
end end

View file

@ -5,10 +5,74 @@
require 'spec_helper' require 'spec_helper'
describe AccountDeletion do describe AccountDeletion do
it 'assigns the diaspora_handle from the person object' do
it 'gets initialized with diaspora_id' do a = AccountDeletion.new(:person => alice.person)
AccountDeletion.new(:diaspora_id => alice.person.diaspora_handle).should be_true a.diaspora_handle.should == alice.person.diaspora_handle
end end
it 'fires a resque job after creation'do
Resque.should_receive(:enqueue).with(Jobs::DeleteAccount, anything)
AccountDeletion.create(:person => alice.person)
end
describe "#perform!" do
before do
@ad = AccountDeletion.new(:person => alice.person)
end
it 'creates a deleter' do
AccountDeleter.should_receive(:new).with(alice.person.diaspora_handle).and_return(stub(:perform! => true))
@ad.perform!
end
it 'dispatches the account deletion if the user exists' do
@ad.should_receive(:dispatch)
@ad.perform!
end
it 'does not dispatch an account deletion for non-local people' do
deletion = AccountDeletion.new(:person => remote_raphael)
deletion.should_not_receive(:dispatch)
deletion.perform!
end
end
describe '#dispatch' do
it "sends the account deletion xml" do
@ad = AccountDeletion.new(:person => alice.person)
@ad.send(:dispatch)
end end
end
describe "#subscribers" do
it 'includes all contacts' do
@ad = AccountDeletion.new(:person => alice.person)
@ad.person.owner.should_receive(:contact_people).and_return([remote_raphael])
@ad.subscribers(alice).should include(remote_raphael)
end
it 'includes resharers' do
@ad = AccountDeletion.new(:person => alice.person)
p = Factory(:person)
Person.should_receive(:who_have_reshared_a_users_posts).with(alice).and_return([p])
@ad.subscribers(alice).should include(p)
end
end
describe 'serialization' do
before do
account_deletion = AccountDeletion.new(:person => alice.person)
@xml = account_deletion.to_xml.to_s
end
it 'should have a diaspora_handle' do
@xml.include?(alice.person.diaspora_handle).should == true
end
it 'marshals the xml' do
AccountDeletion.from_xml(@xml).should be_valid
end
end
end

View file

@ -6,25 +6,12 @@ require 'spec_helper'
describe Jobs::DeleteAccount do describe Jobs::DeleteAccount do
describe '#perform' do describe '#perform' do
it 'calls remove_all_traces' do it 'performs the account deletion' do
stub_find_for(bob) account_deletion = stub
bob.should_receive(:remove_all_traces) AccountDeletion.stub(:find).and_return(account_deletion)
Jobs::DeleteAccount.perform(bob.id) account_deletion.should_receive(:perform!)
end
it 'calls destroy' do Jobs::DeleteAccount.perform(1)
stub_find_for(bob)
bob.should_receive(:destroy)
Jobs::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 end
end end

View file

@ -91,6 +91,14 @@ describe Person do
Person.all_from_aspects(aspect_ids, bob).map(&:id).should == [] Person.all_from_aspects(aspect_ids, bob).map(&:id).should == []
end end
end end
describe ".who_have_reshared a user's posts" do
it 'pulls back users who reshared the status message of a user' do
sm = Factory.create(:status_message, :author => alice.person, :public => true)
reshare = Factory.create(:reshare, :root => sm)
Person.who_have_reshared_a_users_posts(alice).should == [reshare.author]
end
end
end end
describe "delegating" do describe "delegating" do
@ -537,18 +545,21 @@ describe Person do
end end
end end
describe "#close_account!" do describe '#lock_access!' do
it 'sets the closed_account flag' do
@person.lock_access!
@person.reload.closed_account.should be_true
end
end
describe "#clear_profile!!" do
before do before do
@person = Factory(:person) @person = Factory(:person)
end end
it 'sets the closed_account flag' do
@person.close_account!
@person.reload.closed_account.should be_true
end
it 'calls Profile#tombstone!' do it 'calls Profile#tombstone!' do
@person.profile.should_receive(:tombstone!) @person.profile.should_receive(:tombstone!)
@person.close_account! @person.clear_profile!
end end
end end
end end

View file

@ -66,6 +66,15 @@ describe StatusMessage do
end end
end end
describe ".guids_for_author" do
it 'returns an array of the status_message guids' do
sm1 = Factory(:status_message, :author => alice.person)
sm2 = Factory(:status_message, :author => bob.person)
guids = StatusMessage.guids_for_author(alice.person)
guids.should == [sm1.guid]
end
end
describe '.before_create' do describe '.before_create' do
it 'calls build_tags' do it 'calls build_tags' do
status = Factory.build(:status_message) status = Factory.build(:status_message)

View file

@ -1010,20 +1010,35 @@ describe User do
end end
describe "#close_account!" do describe "#close_account!" do
before do it 'locks the user out' do
@user = Factory.create(:user) @user.close_account!
@user.reload.access_locked?.should be_true
end end
it 'creates an account deletion' do
expect{
@user.close_account!
}.to change(AccountDeletion, :count).by(1)
end
it 'calls person#lock_access!' do
@user.person.should_receive(:lock_access!)
@user.close_account!
end
end
describe "#clear_account!" do
it 'resets the password to a random string' do it 'resets the password to a random string' do
random_pass = "12345678909876543210" random_pass = "12345678909876543210"
ActiveSupport::SecureRandom.should_receive(:hex).and_return(random_pass) ActiveSupport::SecureRandom.should_receive(:hex).and_return(random_pass)
@user.close_account! @user.clear_account!
@user.valid_password?(random_pass) @user.valid_password?(random_pass)
end end
it 'clears all the clearable fields' do it 'clears all the clearable fields' do
@user.reload @user.reload
attributes = @user.send(:clearable_fields) attributes = @user.send(:clearable_fields)
@user.close_account! @user.clear_account!
@user.reload @user.reload
attributes.each do |attr| attributes.each do |attr|
@ -1059,7 +1074,6 @@ describe User do
authentication_token authentication_token
unconfirmed_email unconfirmed_email
confirm_email_token confirm_email_token
locked_at
show_community_spotlight_in_stream show_community_spotlight_in_stream
}.sort }.sort
end end