diaspora/app/services/migration_service.rb
cmrd Senya f85f167f50 Implement archive import backend
This implements archive import feature.

The feature is divided in two main subfeatures: archive validation and archive import.

Archive validation performs different validation on input user archive. This can be
used without actually running import, e.g. when user wants to check the archive
before import from the frontend. Validators may add messages and modify the archive.

Validators are separated in two types: critical validators and non-critical validators.

If validations by critical validators fail it means we can't import archive.

If non-critical validations fail, we can import archive, but some warning messages
are rendered.

Also validators may change archive contents, e.g. when some entity can't be
imported it may be removed from the archive.

Validators' job is to take away complexity from the importer and perform the validations
which are not implemented in other parts of the system, e.g. DB validations or
diaspora_federation entity validations.

Archive importer then takes the modified archive from the validator and imports it.

In order to incapsulate high-level migration logic a MigrationService is
introduced. MigrationService links ArchiveValidator, ArchiveImporter and
AccountMigration.

Also here is introduced a rake task which may be used by podmins to run archive
import.
2019-04-26 18:41:27 +03:00

76 lines
1.9 KiB
Ruby

# frozen_string_literal: true
class MigrationService
attr_reader :archive_path, :new_user_name
delegate :errors, :warnings, to: :archive_validator
def initialize(archive_path, new_user_name)
@archive_path = archive_path
@new_user_name = new_user_name
end
def validate
archive_validator.validate
raise ArchiveValidationFailed, errors.join("\n") if errors.any?
raise MigrationAlreadyExists if AccountMigration.where(old_person: old_person).any?
end
def perform!
find_or_create_user
import_archive
run_migration
end
# when old person can't be resolved we still import data but we don't create&perform AccountMigration instance
def only_import?
old_person.nil?
end
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?
end
def import_archive
archive_importer.import
end
def run_migration
account_migration.save
account_migration.perform!
end
def account_migration
@account_migration ||= AccountMigration.new(
old_person: old_person,
new_person: archive_importer.user.person,
old_private_key: archive_importer.serialized_private_key,
old_person_diaspora_id: archive_importer.archive_author_diaspora_id
)
end
def old_person
@old_person ||= Person.by_account_identifier(archive_validator.archive_author_diaspora_id)
end
def archive_importer
@archive_importer ||= ArchiveImporter.new(archive_validator.archive_hash)
end
def archive_validator
@archive_validator ||= ArchiveValidator.new(archive_file)
end
def archive_file
# TODO: archive is likely to be a .json.gz file
File.new(archive_path, "r")
end
class ArchiveValidationFailed < RuntimeError
end
class MigrationAlreadyExists < RuntimeError
end
end