AccountMigration: support chained migration case
This commit is contained in:
parent
dd9ac758e8
commit
597d9e0275
2 changed files with 122 additions and 36 deletions
|
|
@ -81,6 +81,10 @@ class AccountMigration < ApplicationRecord
|
||||||
new_person.owner
|
new_person.owner
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def newest_user
|
||||||
|
newest_person.owner
|
||||||
|
end
|
||||||
|
|
||||||
def lock_old_user!
|
def lock_old_user!
|
||||||
old_user&.lock_access!
|
old_user&.lock_access!
|
||||||
end
|
end
|
||||||
|
|
@ -106,7 +110,7 @@ class AccountMigration < ApplicationRecord
|
||||||
# We need to resend contacts of users of our pod for the remote new person so that the remote pod received this
|
# We need to resend contacts of users of our pod for the remote new person so that the remote pod received this
|
||||||
# contact information from the authoritative source.
|
# contact information from the authoritative source.
|
||||||
def dispatch_contacts
|
def dispatch_contacts
|
||||||
new_person.contacts.sharing.each do |contact|
|
newest_person.contacts.sharing.each do |contact|
|
||||||
Diaspora::Federation::Dispatcher.defer_dispatch(contact.user, contact)
|
Diaspora::Federation::Dispatcher.defer_dispatch(contact.user, contact)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -179,7 +183,7 @@ class AccountMigration < ApplicationRecord
|
||||||
def duplicate_person_contacts
|
def duplicate_person_contacts
|
||||||
Contact
|
Contact
|
||||||
.joins("INNER JOIN contacts as c2 ON (contacts.user_id = c2.user_id AND contacts.person_id=#{old_person.id} AND"\
|
.joins("INNER JOIN contacts as c2 ON (contacts.user_id = c2.user_id AND contacts.person_id=#{old_person.id} AND"\
|
||||||
" c2.person_id=#{new_person.id})")
|
" c2.person_id=#{newest_person.id})")
|
||||||
end
|
end
|
||||||
|
|
||||||
def duplicate_person_likes
|
def duplicate_person_likes
|
||||||
|
|
@ -187,7 +191,7 @@ class AccountMigration < ApplicationRecord
|
||||||
.joins("INNER JOIN likes as l2 ON (likes.target_id = l2.target_id "\
|
.joins("INNER JOIN likes as l2 ON (likes.target_id = l2.target_id "\
|
||||||
"AND likes.target_type = l2.target_type "\
|
"AND likes.target_type = l2.target_type "\
|
||||||
"AND likes.author_id=#{old_person.id} AND"\
|
"AND likes.author_id=#{old_person.id} AND"\
|
||||||
" l2.author_id=#{new_person.id})")
|
" l2.author_id=#{newest_person.id})")
|
||||||
end
|
end
|
||||||
|
|
||||||
def duplicate_person_participations
|
def duplicate_person_participations
|
||||||
|
|
@ -195,41 +199,41 @@ class AccountMigration < ApplicationRecord
|
||||||
.joins("INNER JOIN participations as p2 ON (participations.target_id = p2.target_id "\
|
.joins("INNER JOIN participations as p2 ON (participations.target_id = p2.target_id "\
|
||||||
"AND participations.target_type = p2.target_type "\
|
"AND participations.target_type = p2.target_type "\
|
||||||
"AND participations.author_id=#{old_person.id} AND"\
|
"AND participations.author_id=#{old_person.id} AND"\
|
||||||
" p2.author_id=#{new_person.id})")
|
" p2.author_id=#{newest_person.id})")
|
||||||
end
|
end
|
||||||
|
|
||||||
def duplicate_person_poll_participations
|
def duplicate_person_poll_participations
|
||||||
PollParticipation
|
PollParticipation
|
||||||
.joins("INNER JOIN poll_participations as p2 ON (poll_participations.poll_id = p2.poll_id "\
|
.joins("INNER JOIN poll_participations as p2 ON (poll_participations.poll_id = p2.poll_id "\
|
||||||
"AND poll_participations.author_id=#{old_person.id} AND"\
|
"AND poll_participations.author_id=#{old_person.id} AND"\
|
||||||
" p2.author_id=#{new_person.id})")
|
" p2.author_id=#{newest_person.id})")
|
||||||
end
|
end
|
||||||
|
|
||||||
def eliminate_user_duplicates
|
def eliminate_user_duplicates
|
||||||
Aspect
|
Aspect
|
||||||
.joins("INNER JOIN aspects as a2 ON (aspects.name = a2.name AND aspects.user_id=#{old_user.id}
|
.joins("INNER JOIN aspects as a2 ON (aspects.name = a2.name AND aspects.user_id=#{old_user.id}
|
||||||
AND a2.user_id=#{new_user.id})")
|
AND a2.user_id=#{newest_user.id})")
|
||||||
.destroy_all
|
.destroy_all
|
||||||
Contact
|
Contact
|
||||||
.joins("INNER JOIN contacts as c2 ON (contacts.person_id = c2.person_id AND contacts.user_id=#{old_user.id} AND"\
|
.joins("INNER JOIN contacts as c2 ON (contacts.person_id = c2.person_id AND contacts.user_id=#{old_user.id} AND"\
|
||||||
" c2.user_id=#{new_user.id})")
|
" c2.user_id=#{newest_user.id})")
|
||||||
.destroy_all
|
.destroy_all
|
||||||
TagFollowing
|
TagFollowing
|
||||||
.joins("INNER JOIN tag_followings as t2 ON (tag_followings.tag_id = t2.tag_id AND"\
|
.joins("INNER JOIN tag_followings as t2 ON (tag_followings.tag_id = t2.tag_id AND"\
|
||||||
" tag_followings.user_id=#{old_user.id} AND t2.user_id=#{new_user.id})")
|
" tag_followings.user_id=#{old_user.id} AND t2.user_id=#{newest_user.id})")
|
||||||
.destroy_all
|
.destroy_all
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_person_references
|
def update_person_references
|
||||||
logger.debug "Updating references from person id=#{old_person.id} to person id=#{new_person.id}"
|
logger.debug "Updating references from person id=#{old_person.id} to person id=#{newest_person.id}"
|
||||||
eliminate_person_duplicates
|
eliminate_person_duplicates
|
||||||
update_references(person_references, old_person, new_person.id)
|
update_references(person_references, old_person, newest_person.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_user_references
|
def update_user_references
|
||||||
logger.debug "Updating references from user id=#{old_user.id} to user id=#{new_user.id}"
|
logger.debug "Updating references from user id=#{old_user.id} to user id=#{newest_user.id}"
|
||||||
eliminate_user_duplicates
|
eliminate_user_duplicates
|
||||||
update_references(user_references, old_user, new_user.id)
|
update_references(user_references, old_user, newest_user.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_references(references, object, new_id)
|
def update_references(references, object, new_id)
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,36 @@ shared_examples_for "migration scenarios initiated locally" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
shared_examples_for "migration scenarios with local user rename" do
|
||||||
|
it "updates user references" do
|
||||||
|
invited_user = FactoryGirl.create(:user, invited_by: old_user)
|
||||||
|
aspect = FactoryGirl.create(:aspect, user: old_user, name: r_str)
|
||||||
|
contact = FactoryGirl.create(:contact, user: old_user)
|
||||||
|
service = FactoryGirl.create(:service, user: old_user)
|
||||||
|
pref = UserPreference.create!(user: old_user, email_type: "also_commented")
|
||||||
|
tag_following = FactoryGirl.create(:tag_following, user: old_user)
|
||||||
|
block = FactoryGirl.create(:block, user: old_user)
|
||||||
|
notification = FactoryGirl.create(:notification, recipient: old_user)
|
||||||
|
report = FactoryGirl.create(:report, user: old_user)
|
||||||
|
authorization = FactoryGirl.create(:auth_with_read, user: old_user)
|
||||||
|
share_visibility = FactoryGirl.create(:share_visibility, user: old_user)
|
||||||
|
|
||||||
|
run_migration
|
||||||
|
|
||||||
|
expect(invited_user.reload.invited_by).to eq(new_user)
|
||||||
|
expect(aspect.reload.user).to eq(new_user)
|
||||||
|
expect(contact.reload.user).to eq(new_user)
|
||||||
|
expect(service.reload.user).to eq(new_user)
|
||||||
|
expect(pref.reload.user).to eq(new_user)
|
||||||
|
expect(tag_following.reload.user).to eq(new_user)
|
||||||
|
expect(block.reload.user).to eq(new_user)
|
||||||
|
expect(notification.reload.recipient).to eq(new_user)
|
||||||
|
expect(report.reload.user).to eq(new_user)
|
||||||
|
expect(authorization.reload.user).to eq(new_user)
|
||||||
|
expect(share_visibility.reload.user).to eq(new_user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "account migration" do
|
describe "account migration" do
|
||||||
# this is the case when we receive account migration message from the federation
|
# this is the case when we receive account migration message from the federation
|
||||||
context "remotely initiated" do
|
context "remotely initiated" do
|
||||||
|
|
@ -173,6 +203,22 @@ describe "account migration" do
|
||||||
include_examples "every migration scenario"
|
include_examples "every migration scenario"
|
||||||
|
|
||||||
include_examples "migration scenarios initiated remotely"
|
include_examples "migration scenarios initiated remotely"
|
||||||
|
|
||||||
|
context "when new person has been migrated before" do
|
||||||
|
let(:intermidiate_person) { create_remote_user("remote-d.net").person }
|
||||||
|
|
||||||
|
before do
|
||||||
|
AccountMigration.create!(old_person: intermidiate_person, new_person: new_person).perform!
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_migration
|
||||||
|
AccountMigration.create!(old_person: old_person, new_person: intermidiate_person).perform!
|
||||||
|
end
|
||||||
|
|
||||||
|
include_examples "every migration scenario"
|
||||||
|
|
||||||
|
include_examples "migration scenarios initiated remotely"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# this is the case when we're a pod, which was left by a person in favor of remote one
|
# this is the case when we're a pod, which was left by a person in favor of remote one
|
||||||
|
|
@ -200,6 +246,24 @@ describe "account migration" do
|
||||||
user.reload
|
user.reload
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "when new person has been migrated before" do
|
||||||
|
let(:intermidiate_person) { create_remote_user("remote-d.net").person }
|
||||||
|
|
||||||
|
before do
|
||||||
|
AccountMigration.create!(old_person: intermidiate_person, new_person: new_person).perform!
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_migration
|
||||||
|
AccountMigration.create!(old_person: old_user.person, new_person: intermidiate_person).perform!
|
||||||
|
end
|
||||||
|
|
||||||
|
include_examples "every migration scenario"
|
||||||
|
|
||||||
|
include_examples "migration scenarios initiated remotely"
|
||||||
|
|
||||||
|
it_behaves_like "migration scenarios with local old user"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -228,6 +292,24 @@ describe "account migration" do
|
||||||
it_behaves_like "migration scenarios initiated locally" do
|
it_behaves_like "migration scenarios initiated locally" do
|
||||||
let!(:remote_contact) { create_remote_contact(new_user, "remote-friend.org") }
|
let!(:remote_contact) { create_remote_contact(new_user, "remote-friend.org") }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "when new person has been migrated before" do
|
||||||
|
let(:intermidiate_person) { FactoryGirl.create(:user).person }
|
||||||
|
|
||||||
|
before do
|
||||||
|
AccountMigration.create!(old_person: intermidiate_person, new_person: new_person).perform!
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_migration
|
||||||
|
AccountMigration.create!(
|
||||||
|
old_person: old_person,
|
||||||
|
new_person: intermidiate_person,
|
||||||
|
old_private_key: old_user.serialized_private_key
|
||||||
|
).perform!
|
||||||
|
end
|
||||||
|
|
||||||
|
include_examples "every migration scenario"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# this is the case when a user changes diaspora id but stays on the same pod
|
# this is the case when a user changes diaspora id but stays on the same pod
|
||||||
|
|
@ -254,32 +336,32 @@ describe "account migration" do
|
||||||
expect(old_user.reload).to be_a_clear_account
|
expect(old_user.reload).to be_a_clear_account
|
||||||
end
|
end
|
||||||
|
|
||||||
it "updates user references" do
|
include_examples "migration scenarios with local user rename"
|
||||||
invited_user = FactoryGirl.create(:user, invited_by: old_user)
|
|
||||||
aspect = FactoryGirl.create(:aspect, user: old_user, name: r_str)
|
|
||||||
contact = FactoryGirl.create(:contact, user: old_user)
|
|
||||||
service = FactoryGirl.create(:service, user: old_user)
|
|
||||||
pref = UserPreference.create!(user: old_user, email_type: "also_commented")
|
|
||||||
tag_following = FactoryGirl.create(:tag_following, user: old_user)
|
|
||||||
block = FactoryGirl.create(:block, user: old_user)
|
|
||||||
notification = FactoryGirl.create(:notification, recipient: old_user)
|
|
||||||
report = FactoryGirl.create(:report, user: old_user)
|
|
||||||
authorization = FactoryGirl.create(:auth_with_read, user: old_user)
|
|
||||||
share_visibility = FactoryGirl.create(:share_visibility, user: old_user)
|
|
||||||
|
|
||||||
run_migration
|
context "when new user has been migrated before" do
|
||||||
|
let(:intermidiate_person) { FactoryGirl.create(:user).person }
|
||||||
|
|
||||||
expect(invited_user.reload.invited_by).to eq(new_user)
|
before do
|
||||||
expect(aspect.reload.user).to eq(new_user)
|
AccountMigration.create!(old_person: intermidiate_person, new_person: new_person).perform!
|
||||||
expect(contact.reload.user).to eq(new_user)
|
end
|
||||||
expect(service.reload.user).to eq(new_user)
|
|
||||||
expect(pref.reload.user).to eq(new_user)
|
def run_migration
|
||||||
expect(tag_following.reload.user).to eq(new_user)
|
AccountMigration.create!(
|
||||||
expect(block.reload.user).to eq(new_user)
|
old_person: old_person,
|
||||||
expect(notification.reload.recipient).to eq(new_user)
|
new_person: intermidiate_person
|
||||||
expect(report.reload.user).to eq(new_user)
|
).perform!
|
||||||
expect(authorization.reload.user).to eq(new_user)
|
end
|
||||||
expect(share_visibility.reload.user).to eq(new_user)
|
|
||||||
|
include_examples "every migration scenario"
|
||||||
|
|
||||||
|
it_behaves_like "migration scenarios with local old user"
|
||||||
|
|
||||||
|
it "clears the old user account" do
|
||||||
|
run_migration
|
||||||
|
expect(old_user.reload).to be_a_clear_account
|
||||||
|
end
|
||||||
|
|
||||||
|
include_examples "migration scenarios with local user rename"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue