Allow to choose to overwrite settings and profile data

This commit is contained in:
Benjamin Neff 2021-11-09 04:04:27 +01:00
parent 96493b4a5c
commit 34528521f2
No known key found for this signature in database
GPG key ID: 971464C3F1A90194
5 changed files with 179 additions and 53 deletions

View file

@ -3,14 +3,14 @@
class ImportService class ImportService
include Diaspora::Logging include Diaspora::Logging
def import_by_user(user) def import_by_user(user, opts={})
import_by_files(user.export.current_path, user.exported_photos_file.current_path, user.username) import_by_files(user.export.current_path, user.exported_photos_file.current_path, user.username, opts)
end 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? if path_to_profile.present?
logger.info "Import for profile #{username} at path #{path_to_profile} requested" 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 end
user = User.find_by(username: username) user = User.find_by(username: username)
@ -25,10 +25,10 @@ class ImportService
private 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) 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}" logger.info "Start validating user profile #{username}"
service.validate service.validate
logger.info "Start importing user profile for '#{username}'" logger.info "Start importing user profile for '#{username}'"

View file

@ -1,12 +1,14 @@
# frozen_string_literal: true # frozen_string_literal: true
class MigrationService class MigrationService
attr_reader :archive_path, :new_user_name attr_reader :archive_path, :new_user_name, :opts
delegate :errors, :warnings, to: :archive_validator 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 @archive_path = archive_path
@new_user_name = new_user_name @new_user_name = new_user_name
@opts = opts
end end
def validate def validate
@ -40,12 +42,11 @@ class MigrationService
private private
def find_or_create_user def find_or_create_user
archive_importer.user = User.find_by(username: new_user_name) archive_importer.find_or_create_user(username: new_user_name, password: SecureRandom.hex)
archive_importer.create_user(username: new_user_name, password: SecureRandom.hex) if archive_importer.user.nil?
end end
def import_archive def import_archive
archive_importer.import archive_importer.import(opts)
end end
def run_migration def run_migration

View file

@ -10,7 +10,7 @@ class ArchiveImporter
@archive_hash = archive_hash @archive_hash = archive_hash
end end
def import def import(opts={})
import_tag_followings import_tag_followings
import_aspects import_aspects
import_contacts import_contacts
@ -19,12 +19,12 @@ class ArchiveImporter
import_subscriptions import_subscriptions
import_others_relayables import_others_relayables
import_blocks import_blocks
import_settings if opts.fetch(:import_settings, true)
import_profile if opts.fetch(:import_profile, true)
end end
def create_user(attr) def find_or_create_user(attr)
allowed_keys = %w[ allowed_keys = %w[email language]
email strip_exif show_community_spotlight_in_stream language disable_mail auto_follow_back
]
data = convert_keys(archive_hash["user"], allowed_keys) 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 # setting getting_started to false as the user doesn't need to see the getting started wizard
data.merge!( data.merge!(
@ -36,8 +36,6 @@ class ArchiveImporter
} }
) )
self.user = User.find_or_build(data) 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.getting_started = false
user.save! user.save!
end end
@ -63,7 +61,7 @@ class ArchiveImporter
return if name.nil? return if name.nil?
aspect = user.aspects.find_by(name: name) 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 end
def import_aspects def import_aspects
@ -74,7 +72,6 @@ class ArchiveImporter
logger.warn "#{self}: #{e}" logger.warn "#{self}: #{e}"
end end
end end
set_auto_follow_back_aspect
end end
def import_posts def import_posts
@ -125,6 +122,21 @@ class ArchiveImporter
end end
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) def convert_keys(hash, allowed_keys)
hash hash
.slice(*allowed_keys) .slice(*allowed_keys)

View file

@ -2,13 +2,16 @@
namespace :accounts do namespace :accounts do
desc "Perform migration" desc "Perform migration"
task :migration, %i[archive_path photos_path new_user_name] => :environment do |_t, args| task :migration,
puts "Account migration is requested. You can import a profile or a photos archive or booth." %i[archive_path photos_path new_user_name import_settings import_profile] => :environment do |_t, args|
args = %i[archive_path photos_path new_user_name].map {|name| [name, args[name]] }.to_h 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) process_arguments(args)
start_time = Time.now.getlocal start_time = Time.now.getlocal
if args[:new_user_name].present? && (args[:archive_path].present? || args[:photos_path].present?) 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)" puts "\n Migration completed in #{Time.now.getlocal - start_time} seconds. (Photos might still be processed in)"
else else
puts "Must set a user name and a archive file path or photos file path" 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[: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[: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[: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 "Archive path: #{args[:archive_path]}"
puts "Photos path: #{args[:photos_path]}" puts "Photos path: #{args[:photos_path]}"
puts "New username: #{args[:new_user_name]}" 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
end end
def request_parameter(arg, text)
return arg unless arg.nil?
print text
$stdin.gets.strip
end

View file

@ -56,17 +56,13 @@ describe ArchiveImporter do
let(:archive_hash) { let(:archive_hash) {
{ {
"user" => { "user" => {
"auto_follow_back_aspect" => "Friends", "profile" => {
"profile" => {
"entity_data" => { "entity_data" => {
"author" => "old_id@old_pod.nowhere" "author" => "old_id@old_pod.nowhere"
} }
}, },
"contact_groups" => [{ "followed_tags" => [target.tag_followings.first.tag.name],
"name" => "Friends" "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 }.not_to raise_error
end end
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 end
describe "#create_user" do describe "#find_or_create_user" do
let(:archive_importer) { ArchiveImporter.new(archive_hash) }
let(:archive_hash) { let(:archive_hash) {
{ {
"user" => { "user" => {
"profile" => { "profile" => {
"entity_data" => { "entity_data" => {
"author" => "old_id@old_pod.nowhere", "author" => "old_id@old_pod.nowhere",
"first_name" => "First", "first_name" => "First",
@ -133,26 +237,17 @@ describe ArchiveImporter do
"tag_string" => "#diaspora #linux #partying" "tag_string" => "#diaspora #linux #partying"
} }
}, },
"email" => "user@example.com", "email" => "user@example.com"
"strip_exif" => false,
"show_community_spotlight_in_stream" => false,
"language" => "ru",
"disable_mail" => false,
"auto_follow_back" => true
} }
} }
} }
let(:archive_importer) { ArchiveImporter.new(archive_hash) }
it "creates user" do it "creates user" do
expect { 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) }.to change(User, :count).by(1)
expect(archive_importer.user.email).to eq("user@example.com") 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.getting_started).to be_falsey
expect(archive_importer.user.profile.first_name).to eq("First") expect(archive_importer.user.profile.first_name).to eq("First")