diff --git a/app/services/import_service.rb b/app/services/import_service.rb index 13ca0654a..9185ee90c 100644 --- a/app/services/import_service.rb +++ b/app/services/import_service.rb @@ -3,14 +3,14 @@ class ImportService include Diaspora::Logging - def import_by_user(user) - import_by_files(user.export.current_path, user.exported_photos_file.current_path, user.username) + def import_by_user(user, opts={}) + import_by_files(user.export.current_path, user.exported_photos_file.current_path, user.username, opts) end - def import_by_files(path_to_profile, path_to_photos, username) + def import_by_files(path_to_profile, path_to_photos, username, opts={}) if path_to_profile.present? logger.info "Import for profile #{username} at path #{path_to_profile} requested" - import_user_profile(path_to_profile, username) + import_user_profile(path_to_profile, username, opts) end user = User.find_by(username: username) @@ -25,10 +25,10 @@ class ImportService private - def import_user_profile(path_to_profile, username) + def import_user_profile(path_to_profile, username, opts) raise ArgumentError, "Profile file not found at path: #{path_to_profile}" unless File.exist?(path_to_profile) - service = MigrationService.new(path_to_profile, username) + service = MigrationService.new(path_to_profile, username, opts) logger.info "Start validating user profile #{username}" service.validate logger.info "Start importing user profile for '#{username}'" diff --git a/app/services/migration_service.rb b/app/services/migration_service.rb index 56c13a45b..0e6b0d917 100644 --- a/app/services/migration_service.rb +++ b/app/services/migration_service.rb @@ -1,12 +1,14 @@ # frozen_string_literal: true class MigrationService - attr_reader :archive_path, :new_user_name + attr_reader :archive_path, :new_user_name, :opts + delegate :errors, :warnings, to: :archive_validator - def initialize(archive_path, new_user_name) + def initialize(archive_path, new_user_name, opts={}) @archive_path = archive_path @new_user_name = new_user_name + @opts = opts end def validate @@ -40,12 +42,11 @@ class MigrationService private def find_or_create_user - archive_importer.user = User.find_by(username: new_user_name) - archive_importer.create_user(username: new_user_name, password: SecureRandom.hex) if archive_importer.user.nil? + archive_importer.find_or_create_user(username: new_user_name, password: SecureRandom.hex) end def import_archive - archive_importer.import + archive_importer.import(opts) end def run_migration diff --git a/lib/archive_importer.rb b/lib/archive_importer.rb index 1b0bab6cb..8776edca8 100644 --- a/lib/archive_importer.rb +++ b/lib/archive_importer.rb @@ -10,7 +10,7 @@ class ArchiveImporter @archive_hash = archive_hash end - def import + def import(opts={}) import_tag_followings import_aspects import_contacts @@ -19,12 +19,12 @@ class ArchiveImporter import_subscriptions import_others_relayables import_blocks + import_settings if opts.fetch(:import_settings, true) + import_profile if opts.fetch(:import_profile, true) end - def create_user(attr) - allowed_keys = %w[ - email strip_exif show_community_spotlight_in_stream language disable_mail auto_follow_back - ] + def find_or_create_user(attr) + allowed_keys = %w[email language] data = convert_keys(archive_hash["user"], allowed_keys) # setting getting_started to false as the user doesn't need to see the getting started wizard data.merge!( @@ -36,8 +36,6 @@ class ArchiveImporter } ) self.user = User.find_or_build(data) - user.show_community_spotlight_in_stream = data.fetch(:show_community_spotlight_in_stream, true) - user.strip_exif = data.fetch(:strip_exif, true) user.getting_started = false user.save! end @@ -63,7 +61,7 @@ class ArchiveImporter return if name.nil? aspect = user.aspects.find_by(name: name) - user.update(auto_follow_back_aspect: aspect) if aspect + user.update(auto_follow_back: true, auto_follow_back_aspect: aspect) if aspect end def import_aspects @@ -74,7 +72,6 @@ class ArchiveImporter logger.warn "#{self}: #{e}" end end - set_auto_follow_back_aspect end def import_posts @@ -125,6 +122,21 @@ class ArchiveImporter end end + def import_settings + allowed_keys = %w[language show_community_spotlight_in_stream strip_exif] + convert_keys(archive_hash["user"], allowed_keys).each do |key, value| + user.update(key => value) unless value.nil? + end + + set_auto_follow_back_aspect if archive_hash.fetch("user").fetch("auto_follow_back", false) + end + + def import_profile + profile_attributes.each do |key, value| + user.person.profile.update(key => value) unless value.nil? + end + end + def convert_keys(hash, allowed_keys) hash .slice(*allowed_keys) diff --git a/lib/tasks/accounts.rake b/lib/tasks/accounts.rake index 24077ec3e..f6075de3d 100644 --- a/lib/tasks/accounts.rake +++ b/lib/tasks/accounts.rake @@ -2,13 +2,16 @@ namespace :accounts do desc "Perform migration" - task :migration, %i[archive_path photos_path new_user_name] => :environment do |_t, args| - puts "Account migration is requested. You can import a profile or a photos archive or booth." - args = %i[archive_path photos_path new_user_name].map {|name| [name, args[name]] }.to_h + task :migration, + %i[archive_path photos_path new_user_name import_settings import_profile] => :environment do |_t, args| + puts "Account migration is requested. You can import a profile or a photos archive or both." + args = %i[archive_path photos_path new_user_name import_settings import_profile] + .map {|name| [name, args[name]] }.to_h process_arguments(args) start_time = Time.now.getlocal if args[:new_user_name].present? && (args[:archive_path].present? || args[:photos_path].present?) - ImportService.new.import_by_files(args[:archive_path], args[:photos_path], args[:new_user_name]) + ImportService.new.import_by_files(args[:archive_path], args[:photos_path], args[:new_user_name], + args.slice(:import_settings, :import_profile)) puts "\n Migration completed in #{Time.now.getlocal - start_time} seconds. (Photos might still be processed in)" else puts "Must set a user name and a archive file path or photos file path" @@ -19,16 +22,31 @@ namespace :accounts do args[:archive_path] = request_parameter(args[:archive_path], "Enter the archive (.json, .gz, .zip) path: ") args[:photos_path] = request_parameter(args[:photos_path], "Enter the photos (.zip) path: ") args[:new_user_name] = request_parameter(args[:new_user_name], "Enter the new user name: ") + args[:import_settings] = request_boolean_parameter(args[:import_settings], "Import and overwrite settings [Y/n]: ") + args[:import_profile] = request_boolean_parameter(args[:import_profile], "Import and overwrite profile [Y/n]: ") puts "Archive path: #{args[:archive_path]}" puts "Photos path: #{args[:photos_path]}" puts "New username: #{args[:new_user_name]}" + puts "Import settings: #{args[:import_settings]}" + puts "Import profile: #{args[:import_profile]}" + end + + def request_parameter(arg, text) + return arg unless arg.nil? + + print text + $stdin.gets.strip + end + + def request_boolean_parameter(arg, text, default: true) + return arg == "true" unless arg.nil? + + print text + response = $stdin.gets.strip.downcase + + return default if response == "" + + response[0] == "y" end end - -def request_parameter(arg, text) - return arg unless arg.nil? - - print text - $stdin.gets.strip -end diff --git a/spec/lib/archive_importer_spec.rb b/spec/lib/archive_importer_spec.rb index 6ee361067..1579371c9 100644 --- a/spec/lib/archive_importer_spec.rb +++ b/spec/lib/archive_importer_spec.rb @@ -56,17 +56,13 @@ describe ArchiveImporter do let(:archive_hash) { { "user" => { - "auto_follow_back_aspect" => "Friends", - "profile" => { + "profile" => { "entity_data" => { "author" => "old_id@old_pod.nowhere" } }, - "contact_groups" => [{ - "name" => "Friends" - }], - "followed_tags" => [target.tag_followings.first.tag.name], - "post_subscriptions" => [target.participations.first.target.guid] + "followed_tags" => [target.tag_followings.first.tag.name], + "post_subscriptions" => [target.participations.first.target.guid] } } } @@ -109,14 +105,122 @@ describe ArchiveImporter do }.not_to raise_error end end + + context "with settings" do + let(:archive_hash) { + { + "user" => { + "profile" => { + "entity_data" => { + "author" => "old_id@old_pod.nowhere" + } + }, + "contact_groups" => [{ + "name" => "Follow" + }], + "strip_exif" => false, + "show_community_spotlight_in_stream" => false, + "language" => "ru", + "auto_follow_back" => true, + "auto_follow_back_aspect" => "Follow" + } + } + } + + it "imports the settings" do + expect { + archive_importer.import + }.not_to raise_error + + expect(archive_importer.user.strip_exif).to eq(false) + expect(archive_importer.user.show_community_spotlight_in_stream).to eq(false) + expect(archive_importer.user.language).to eq("ru") + expect(archive_importer.user.auto_follow_back).to eq(true) + expect(archive_importer.user.auto_follow_back_aspect.name).to eq("Follow") + end + + it "does not overwrite settings if import_settings is disabled" do + expect { + archive_importer.import(import_settings: false) + }.not_to raise_error + + expect(archive_importer.user.strip_exif).to eq(true) + expect(archive_importer.user.show_community_spotlight_in_stream).to eq(true) + expect(archive_importer.user.language).to eq("en") + expect(archive_importer.user.auto_follow_back).to eq(false) + end + end + + context "with profile" do + let(:archive_hash) { + { + "user" => { + "profile" => { + "entity_data" => { + "author" => "old_id@old_pod.nowhere", + "first_name" => "First", + "last_name" => "Last", + "full_name" => "Full Name", + "image_url" => "https://example.com/my_avatar.png", + "bio" => "I'm just a test account", + "gender" => "Robot", + "birthday" => "2006-01-01", + "location" => "diaspora* specs", + "searchable" => false, + "public" => true, + "nsfw" => true, + "tag_string" => "#diaspora #linux #partying" + } + } + } + } + } + + it "imports the profile data" do + expect { + archive_importer.import + }.not_to raise_error + + expect(archive_importer.user.profile.first_name).to eq("First") + expect(archive_importer.user.profile.last_name).to eq("Last") + expect(archive_importer.user.profile.image_url).to eq("https://example.com/my_avatar.png") + expect(archive_importer.user.profile.bio).to eq("I'm just a test account") + expect(archive_importer.user.profile.gender).to eq("Robot") + expect(archive_importer.user.profile.birthday).to eq(Date.new(2006, 1, 1)) + expect(archive_importer.user.profile.location).to eq("diaspora* specs") + expect(archive_importer.user.profile.searchable).to eq(false) + expect(archive_importer.user.profile.public_details).to eq(true) + expect(archive_importer.user.profile.nsfw).to eq(true) + expect(archive_importer.user.profile.tag_string).to eq("#diaspora #linux #partying") + end + + it "does not overwrite profile if import_profile is disabled" do + original_profile = target.profile.dup + + expect { + archive_importer.import(import_profile: false) + }.not_to raise_error + + expect(archive_importer.user.profile.first_name).to eq(original_profile.first_name) + expect(archive_importer.user.profile.last_name).to eq(original_profile.last_name) + expect(archive_importer.user.profile.image_url).to eq(original_profile.image_url) + expect(archive_importer.user.profile.bio).to eq(original_profile.bio) + expect(archive_importer.user.profile.gender).to eq(original_profile.gender) + expect(archive_importer.user.profile.birthday).to eq(original_profile.birthday) + expect(archive_importer.user.profile.location).to eq(original_profile.location) + expect(archive_importer.user.profile.searchable).to eq(original_profile.searchable) + expect(archive_importer.user.profile.public_details).to eq(original_profile.public_details) + expect(archive_importer.user.profile.nsfw).to eq(original_profile.nsfw) + expect(archive_importer.user.profile.tag_string).to eq(original_profile.tag_string) + end + end end - describe "#create_user" do - let(:archive_importer) { ArchiveImporter.new(archive_hash) } + describe "#find_or_create_user" do let(:archive_hash) { { "user" => { - "profile" => { + "profile" => { "entity_data" => { "author" => "old_id@old_pod.nowhere", "first_name" => "First", @@ -133,26 +237,17 @@ describe ArchiveImporter do "tag_string" => "#diaspora #linux #partying" } }, - "email" => "user@example.com", - "strip_exif" => false, - "show_community_spotlight_in_stream" => false, - "language" => "ru", - "disable_mail" => false, - "auto_follow_back" => true + "email" => "user@example.com" } } } + let(:archive_importer) { ArchiveImporter.new(archive_hash) } it "creates user" do expect { - archive_importer.create_user(username: "new_name", password: "123456") + archive_importer.find_or_create_user(username: "new_name", password: "123456") }.to change(User, :count).by(1) expect(archive_importer.user.email).to eq("user@example.com") - expect(archive_importer.user.strip_exif).to eq(false) - expect(archive_importer.user.show_community_spotlight_in_stream).to eq(false) - expect(archive_importer.user.language).to eq("ru") - expect(archive_importer.user.disable_mail).to eq(false) - expect(archive_importer.user.auto_follow_back).to eq(true) expect(archive_importer.user.getting_started).to be_falsey expect(archive_importer.user.profile.first_name).to eq("First")