374 lines
13 KiB
Ruby
374 lines
13 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "integration/federation/federation_helper"
|
|
|
|
def create_remote_contact(user, pod_host)
|
|
FactoryBot.create(
|
|
:contact,
|
|
user: user,
|
|
person: FactoryBot.create(
|
|
:person,
|
|
pod: Pod.find_or_create_by(url: "http://#{pod_host}"),
|
|
diaspora_handle: "#{r_str}@#{pod_host}"
|
|
)
|
|
)
|
|
end
|
|
|
|
shared_examples_for "every migration scenario" do
|
|
it "updates person references" do
|
|
contact = FactoryBot.create(:contact, person: old_person)
|
|
post = FactoryBot.create(:status_message, author: old_person)
|
|
reshare = FactoryBot.create(:reshare, author: old_person)
|
|
photo = FactoryBot.create(:photo, author: old_person)
|
|
comment = FactoryBot.create(:comment, author: old_person)
|
|
like = FactoryBot.create(:like, author: old_person)
|
|
participation = FactoryBot.create(:participation, author: old_person)
|
|
poll_participation = FactoryBot.create(:poll_participation, author: old_person)
|
|
mention = FactoryBot.create(:mention, person: old_person)
|
|
message = FactoryBot.create(:message, author: old_person)
|
|
conversation = FactoryBot.create(:conversation, author: old_person)
|
|
block = FactoryBot.create(:user).blocks.create(person: old_person)
|
|
role = FactoryBot.create(:role, person: old_person)
|
|
|
|
# Create ConversationVisibility by creating a conversation with participants
|
|
conversation2 = FactoryBot.build(:conversation)
|
|
FactoryBot.create(:contact, user: old_user, person: conversation2.author) if old_person.local?
|
|
conversation2.participants << old_person
|
|
conversation2.save!
|
|
visibility = ConversationVisibility.find_by(person_id: old_person.id)
|
|
|
|
# In order to create a notification actor we need to create a notification first
|
|
notification = FactoryBot.build(:notification)
|
|
notification.actors << old_person
|
|
notification.save!
|
|
actor = notification.notification_actors.find_by(person_id: old_person.id)
|
|
|
|
run_migration
|
|
|
|
expect(contact.reload.person).to eq(new_person)
|
|
expect(post.reload.author).to eq(new_person)
|
|
expect(reshare.reload.author).to eq(new_person)
|
|
expect(photo.reload.author).to eq(new_person)
|
|
expect(comment.reload.author).to eq(new_person)
|
|
expect(like.reload.author).to eq(new_person)
|
|
expect(participation.reload.author).to eq(new_person)
|
|
expect(poll_participation.reload.author).to eq(new_person)
|
|
expect(mention.reload.person).to eq(new_person)
|
|
expect(message.reload.author).to eq(new_person)
|
|
expect(conversation.reload.author).to eq(new_person)
|
|
expect(block.reload.person).to eq(new_person)
|
|
expect(role.reload.person).to eq(new_person)
|
|
|
|
expect(visibility.reload.person).to eq(new_person)
|
|
expect(actor.reload.person).to eq(new_person)
|
|
end
|
|
|
|
describe "old person account is closed and profile is cleared" do
|
|
subject { old_person }
|
|
|
|
before do
|
|
run_migration
|
|
subject.reload
|
|
end
|
|
|
|
include_examples "it makes account closed and clears profile"
|
|
end
|
|
|
|
describe "old person doesn't have any reference left" do
|
|
let(:person) { old_person }
|
|
|
|
before do
|
|
DataGenerator.create(person, :generic_person_data)
|
|
end
|
|
|
|
def account_removal_method
|
|
run_migration
|
|
person.reload
|
|
end
|
|
|
|
include_examples "it removes the person associations"
|
|
|
|
it "removes the person conversations" do
|
|
expect {
|
|
account_removal_method
|
|
}.to change(nil, "conversations empty?") { Conversation.where(author: person).empty? }
|
|
.to(be_truthy)
|
|
.and(change(nil, "conversation visibilities of other participants empty?") {
|
|
ConversationVisibility.where(conversation: Conversation.where(author: person)).empty?
|
|
}.to(be_truthy))
|
|
end
|
|
end
|
|
end
|
|
|
|
shared_examples_for "migration scenarios with local old user" do
|
|
it "locks the old user account" do
|
|
run_migration
|
|
expect(old_user.reload).to be_a_locked_account
|
|
end
|
|
end
|
|
|
|
shared_examples_for "migration scenarios initiated remotely" do
|
|
it "resends known contacts to the new user" do
|
|
2.times do
|
|
contact = FactoryBot.create(:contact, person: old_user.person, sharing: true)
|
|
expect(DiasporaFederation::Federation::Sender).to receive(:private)
|
|
.with(
|
|
contact.user_id,
|
|
"Contact:#{contact.user.diaspora_handle}:#{new_user.diaspora_handle}",
|
|
kind_of(Hash)
|
|
).and_return([])
|
|
end
|
|
|
|
inlined_jobs { run_migration }
|
|
end
|
|
end
|
|
|
|
shared_examples_for "migration scenarios initiated locally" do
|
|
it "dispatches account migration message to the federation" do
|
|
expect(DiasporaFederation::Federation::Sender).to receive(:public) do |sender_id, obj_str, urls, xml|
|
|
if old_user.person.remote?
|
|
expect(sender_id).to eq(old_user.diaspora_handle)
|
|
else
|
|
expect(sender_id).to eq(old_user.id)
|
|
end
|
|
expect(obj_str).to eq("AccountMigration:#{old_user.diaspora_handle}:#{new_user.diaspora_handle}")
|
|
subscribers = [remote_contact.person]
|
|
subscribers.push(old_user) if old_user.person.remote?
|
|
expect(urls).to match_array(subscribers.map(&:url).map {|url| "#{url}receive/public" })
|
|
|
|
entity = nil
|
|
expect {
|
|
magic_env = Nokogiri::XML(xml).root
|
|
entity = DiasporaFederation::Salmon::MagicEnvelope
|
|
.unenvelop(magic_env, old_user.diaspora_handle).payload
|
|
}.not_to raise_error
|
|
|
|
expect(entity).to be_a(DiasporaFederation::Entities::AccountMigration)
|
|
expect(entity.author).to eq(old_user.diaspora_handle)
|
|
expect(entity.profile.author).to eq(new_user.diaspora_handle)
|
|
[]
|
|
end
|
|
|
|
inlined_jobs do
|
|
run_migration
|
|
end
|
|
end
|
|
end
|
|
|
|
shared_examples_for "migration scenarios with local user rename" do
|
|
it "updates user references" do
|
|
invited_user = FactoryBot.create(:user, invited_by: old_user)
|
|
aspect = FactoryBot.create(:aspect, user: old_user, name: r_str)
|
|
contact = FactoryBot.create(:contact, user: old_user)
|
|
service = FactoryBot.create(:service, user: old_user)
|
|
pref = UserPreference.create!(user: old_user, email_type: "also_commented")
|
|
tag_following = FactoryBot.create(:tag_following, user: old_user)
|
|
block = FactoryBot.create(:block, user: old_user)
|
|
notification = FactoryBot.create(:notification, recipient: old_user)
|
|
report = FactoryBot.create(:report, user: old_user)
|
|
authorization = FactoryBot.create(:auth_with_read_scopes, user: old_user)
|
|
share_visibility = FactoryBot.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
|
|
# this is the case when we receive account migration message from the federation
|
|
context "remotely initiated" do
|
|
let(:entity) { create_account_migration_entity(old_user.diaspora_handle, new_user) }
|
|
|
|
def run_migration
|
|
allow_callbacks(%i[queue_public_receive fetch_public_key receive_entity])
|
|
post_message(generate_payload(entity, old_user))
|
|
end
|
|
|
|
context "both new and old profiles are remote" do
|
|
let(:old_user) { remote_user_on_pod_c }
|
|
let(:old_person) { old_user.person }
|
|
let(:new_user) { remote_user_on_pod_b }
|
|
let(:new_person) { new_user.person }
|
|
|
|
it "creates AccountMigration db object" do
|
|
run_migration
|
|
expect(AccountMigration.where(old_person: old_user.person, new_person: new_user.person)).to exist
|
|
end
|
|
|
|
include_examples "every migration scenario"
|
|
|
|
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
|
|
|
|
# this is the case when we're a pod, which was left by a person in favor of remote one
|
|
context "old user is local, new user is remote" do
|
|
let(:old_user) { FactoryBot.create(:user) }
|
|
let(:old_person) { old_user.person }
|
|
let(:new_user) { remote_user_on_pod_b }
|
|
let(:new_person) { new_user.person }
|
|
|
|
include_examples "every migration scenario"
|
|
|
|
include_examples "migration scenarios initiated remotely"
|
|
|
|
it_behaves_like "migration scenarios with local old user"
|
|
|
|
it_behaves_like "deletes all of the user data" do
|
|
let(:user) { old_user }
|
|
|
|
before do
|
|
DataGenerator.create(user, :generic_user_data)
|
|
end
|
|
|
|
def account_removal_method
|
|
run_migration
|
|
user.reload
|
|
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
|
|
|
|
context "locally initiated" do
|
|
before do
|
|
allow(DiasporaFederation.callbacks).to receive(:trigger).and_call_original
|
|
end
|
|
|
|
# this is the case when user migrates to our pod from a remote one
|
|
context "old user is remote and new user is local" do
|
|
let(:old_user) { remote_user_on_pod_c }
|
|
let(:old_person) { old_user.person }
|
|
let(:new_user) { FactoryBot.create(:user) }
|
|
let(:new_person) { new_user.person }
|
|
|
|
def run_migration
|
|
AccountMigration.create!(
|
|
old_person: old_user.person,
|
|
new_person: new_user.person,
|
|
old_private_key: old_user.serialized_private_key
|
|
).perform!
|
|
end
|
|
|
|
include_examples "every migration scenario"
|
|
|
|
it_behaves_like "migration scenarios initiated locally" do
|
|
let!(:remote_contact) { create_remote_contact(new_user, "remote-friend.org") }
|
|
end
|
|
|
|
context "when new person has been migrated before" do
|
|
let(:intermidiate_person) { FactoryBot.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
|
|
|
|
# this is the case when a user changes diaspora id but stays on the same pod
|
|
context "old user is local and new user is local" do
|
|
let(:old_user) { FactoryBot.create(:user) }
|
|
let(:old_person) { old_user.person }
|
|
let(:new_user) { FactoryBot.create(:user) }
|
|
let(:new_person) { new_user.person }
|
|
|
|
def run_migration
|
|
AccountMigration.create!(old_person: old_person, new_person: new_person).perform!
|
|
end
|
|
|
|
include_examples "every migration scenario"
|
|
|
|
it_behaves_like "migration scenarios initiated locally" do
|
|
let!(:remote_contact) { create_remote_contact(old_user, "remote-friend.org") }
|
|
end
|
|
|
|
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"
|
|
|
|
context "when new user has been migrated before" do
|
|
let(:intermidiate_person) { FactoryBot.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
|
|
).perform!
|
|
end
|
|
|
|
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
|