From 1570e3fb9afb6d312c94118f5bae5463021d9bae Mon Sep 17 00:00:00 2001 From: Benjamin Neff <benjamin@coding4coffee.ch> Date: Fri, 29 Oct 2021 03:08:01 +0200 Subject: [PATCH] Migrate remote_photo_path and cleanup old photo uploads If the migration contains a new remote_photo_path migrate all photos of the old person to this path. If the person was local before, cleanup old uploaded files of the photos. closes #8314 --- Changelog.md | 1 + app/models/account_migration.rb | 19 +++++++++ ..._remote_photo_path_to_account_migration.rb | 7 ++++ lib/diaspora/federation/receive.rb | 6 ++- spec/integration/account_migration_spec.rb | 41 +++++++++++++++---- .../receive_federation_messages_spec.rb | 4 +- spec/models/account_migration_spec.rb | 32 ++++++++++++++- 7 files changed, 100 insertions(+), 10 deletions(-) create mode 100644 db/migrate/20211027230348_add_remote_photo_path_to_account_migration.rb diff --git a/Changelog.md b/Changelog.md index b4f8e0e2af..7a7d5eecb5 100644 --- a/Changelog.md +++ b/Changelog.md @@ -22,6 +22,7 @@ * Add username to password-reset mail [#8037](https://github.com/diaspora/diaspora/pull/8037) * Resend account migration and deletion for closed recipients [#8309](https://github.com/diaspora/diaspora/pull/8309) * Add sharing status to hovercards [#8317](https://github.com/diaspora/diaspora/pull/8317) +* Migrate photo URLs and cleanup old uploaded photos [#8314](https://github.com/diaspora/diaspora/pull/8314) # 0.7.15.0 diff --git a/app/models/account_migration.rb b/app/models/account_migration.rb index 8a3c42cabb..274ecdecfb 100644 --- a/app/models/account_migration.rb +++ b/app/models/account_migration.rb @@ -90,6 +90,10 @@ class AccountMigration < ApplicationRecord old_user && new_user end + def includes_photo_migration? + remote_photo_path.present? + end + # 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. def dispatch_contacts @@ -122,6 +126,7 @@ class AccountMigration < ApplicationRecord end def update_all_references + update_remote_photo_path if remotely_initiated? && includes_photo_migration? update_person_references update_user_references if user_changed_id_locally? end @@ -200,6 +205,20 @@ class AccountMigration < ApplicationRecord .destroy_all end + def update_remote_photo_path + Photo.where(author: old_person) + .update_all(remote_photo_path: remote_photo_path) # rubocop:disable Rails/SkipsModelValidations + return unless user_left_our_pod? + + Photo.where(author: old_person).find_in_batches do |batch| + batch.each do |photo| + photo.processed_image = nil + photo.unprocessed_image = nil + logger.warn "Error cleaning up photo #{photo.id}" unless photo.save + end + end + end + def update_person_references logger.debug "Updating references from person id=#{old_person.id} to person id=#{new_person.id}" eliminate_person_duplicates diff --git a/db/migrate/20211027230348_add_remote_photo_path_to_account_migration.rb b/db/migrate/20211027230348_add_remote_photo_path_to_account_migration.rb new file mode 100644 index 0000000000..291d88c956 --- /dev/null +++ b/db/migrate/20211027230348_add_remote_photo_path_to_account_migration.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddRemotePhotoPathToAccountMigration < ActiveRecord::Migration[5.2] + def change + add_column :account_migrations, :remote_photo_path, :text + end +end diff --git a/lib/diaspora/federation/receive.rb b/lib/diaspora/federation/receive.rb index edbdf2b9f7..dd136ac424 100644 --- a/lib/diaspora/federation/receive.rb +++ b/lib/diaspora/federation/receive.rb @@ -31,7 +31,11 @@ module Diaspora profile = profile(entity.profile) return if AccountMigration.exists?(old_person: old_person, new_person: profile.person) - AccountMigration.create!(old_person: old_person, new_person: profile.person).tap do |migration| + AccountMigration.create!( + old_person: old_person, + new_person: profile.person, + remote_photo_path: entity.remote_photo_path + ).tap do |migration| migration.signature = entity.signature if old_person.local? migration.save! end diff --git a/spec/integration/account_migration_spec.rb b/spec/integration/account_migration_spec.rb index 35597edad6..17beba1994 100644 --- a/spec/integration/account_migration_spec.rb +++ b/spec/integration/account_migration_spec.rb @@ -97,9 +97,29 @@ shared_examples_for "migration scenarios initiated locally" do [] end - inlined_jobs do - run_migration - end + inlined_jobs { run_migration } + end + + it "does not change the remote paths" do + photo = FactoryGirl.create(:photo, author: old_person) + remote_photo_path = photo.remote_photo_path + + run_migration + + expect(photo.reload.remote_photo_path).to eq(remote_photo_path) + end +end + +shared_examples_for "remote photo migration" do + it "changes the remote paths of photos of the old person" do + old_photo = FactoryGirl.create(:photo, author: old_person) + new_photo = FactoryGirl.create(:photo, author: new_person) + new_remote_photo_path = old_photo.remote_photo_path + + run_migration + + expect(old_photo.reload.remote_photo_path).to eq("https://diaspora.example.tld/uploads/images/") + expect(new_photo.reload.remote_photo_path).to eq(new_remote_photo_path) end end @@ -125,6 +145,8 @@ describe "account migration" do include_examples "every migration scenario" include_examples "migration scenarios initiated remotely" + + include_examples "remote photo migration" end # this is the case when we're a pod, which was left by a person in favor of remote one @@ -136,6 +158,8 @@ describe "account migration" do include_examples "migration scenarios initiated remotely" + include_examples "remote photo migration" + it_behaves_like "migration scenarios with local old user" it_behaves_like "deletes all of the user data" do @@ -165,9 +189,10 @@ describe "account migration" do def run_migration AccountMigration.create!( - old_person: old_user.person, - new_person: new_user.person, - old_private_key: old_user.serialized_private_key + old_person: old_user.person, + new_person: new_user.person, + old_private_key: old_user.serialized_private_key, + remote_photo_path: "https://diaspora.example.tld/uploads/images/" ).perform! end @@ -184,7 +209,9 @@ describe "account migration" do include_context "with local new user" def run_migration - AccountMigration.create!(old_person: old_user.person, new_person: new_user.person).perform! + AccountMigration.create!(old_person: old_user.person, + new_person: new_user.person, + remote_photo_path: "https://diaspora.example.tld/uploads/images/").perform! end include_examples "every migration scenario" diff --git a/spec/integration/federation/receive_federation_messages_spec.rb b/spec/integration/federation/receive_federation_messages_spec.rb index b53bc97c18..7b29c5738b 100644 --- a/spec/integration/federation/receive_federation_messages_spec.rb +++ b/spec/integration/federation/receive_federation_messages_spec.rb @@ -55,7 +55,9 @@ describe "Receive federation messages feature" do it "receives account migration correctly" do run_migration expect(AccountMigration.where(old_person: sender.person, new_person: new_user.person)).to exist - expect(AccountMigration.find_by(old_person: sender.person, new_person: new_user.person)).to be_performed + account_migration = AccountMigration.find_by(old_person: sender.person, new_person: new_user.person) + expect(account_migration).to be_performed + expect(account_migration.remote_photo_path).to eq("https://diaspora.example.tld/uploads/images/") end it "doesn't run the same migration for the second time" do diff --git a/spec/models/account_migration_spec.rb b/spec/models/account_migration_spec.rb index a5fd24f0a6..91a12ba470 100644 --- a/spec/models/account_migration_spec.rb +++ b/spec/models/account_migration_spec.rb @@ -16,7 +16,9 @@ describe AccountMigration, type: :model do let(:old_person) { FactoryGirl.create(:person) } let(:new_person) { FactoryGirl.create(:person) } let(:account_migration) { - AccountMigration.create!(old_person: old_person, new_person: new_person) + AccountMigration.create!(old_person: old_person, + new_person: new_person, + remote_photo_path: "https://diaspora.example.tld/uploads/images/") } describe "receive" do @@ -125,6 +127,34 @@ describe AccountMigration, type: :model do expect(Diaspora::Federation::Dispatcher).to receive(:defer_dispatch).with(contact.user, contact) account_migration.perform! end + + it "cleans up old local photos" do + photo = FactoryGirl.create(:photo, author: old_person) + photo.processed_image.store!(photo.unprocessed_image) + photo.save! + + account_migration.perform! + + updated_photo = photo.reload + expect(updated_photo.remote_photo_path).to eq("https://diaspora.example.tld/uploads/images/") + expect(updated_photo.processed_image.path).to be_nil + expect(updated_photo.unprocessed_image.path).to be_nil + end + + it "does nothing if migration doesn't contain a new remote_photo_path" do + photo = FactoryGirl.create(:photo, author: old_person) + photo.processed_image.store!(photo.unprocessed_image) + photo.save! + + remote_photo_path = photo.remote_photo_path + + AccountMigration.create!(old_person: old_person, new_person: new_person).perform! + + updated_photo = photo.reload + expect(updated_photo.remote_photo_path).to eq(remote_photo_path) + expect(updated_photo.processed_image.path).not_to be_nil + expect(updated_photo.unprocessed_image.path).not_to be_nil + end end context "with local new and remote old users" do -- GitLab