Skip to content

Commit

Permalink
Addad photos import to rake file
Browse files Browse the repository at this point in the history
  • Loading branch information
tclaus committed Sep 12, 2021
1 parent b1d8146 commit a144219
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 121 deletions.
99 changes: 99 additions & 0 deletions app/services/import_profile_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# frozen_string_literal: true

class ImportProfileService
include Diaspora::Logging

def import_by_user(user)
import_by_files(user.export.current_path, user.exported_photos_file.current_path, user.username)
end

def import_by_files(path_to_profile, path_to_photos, username)
if path_to_profile.present?
logger.info "Import for profile #{username} at path #{path_to_profile} requested"
import_user_profile(path_to_profile, username)
end

user = User.find_by(username: username)
return if user.nil?

if path_to_photos.present?
logger.info("Importing photos from import file for '#{username}' from #{path_to_photos}")
import_user_photos(user, path_to_photos)
end
remove_file_references(user)
end

private

def import_user_profile(path_to_profile, username)
return unless path_to_profile.nil? || File.exist?(path_to_profile)

service = MigrationService.new(path_to_profile, username)
logger.info "Start validating user profile #{username}"
service.validate
logger.info "Start importing user profile for '#{username}'"
service.perform!
logger.info "Successfully imported profile: #{username}"
rescue MigrationService::ArchiveValidationFailed => e
logger.error "Errors in the archive found: #{e.message}"
rescue MigrationService::MigrationAlreadyExists
logger.error "Migration record already exists for the user, can't continue"
rescue MigrationService::SelfMigrationNotAllowed
logger.error "You can't migrate onto your own account"
ensure
service&.remove_intermediate_file
end

def import_user_photos(user, path_to_photos)
return if path_to_photos.nil?

return unless File.exist?(path_to_photos)

uncompressed_photos_folder = unzip_photos_file(path_to_photos)
user.posts.find_in_batches do |posts|
import_photos_for_posts(posts, uncompressed_photos_folder)
end
end

def import_photos_for_posts(posts, source_dir)
posts.each do |post|
post.photos.each do |photo|
uploaded_file = "#{source_dir}/#{photo.remote_photo_name}"
next unless File.exist?(uploaded_file) && photo.remote_photo_name.present?

File.open(uploaded_file) do |file|
photo.random_string = File.basename(uploaded_file, ".*")
photo.unprocessed_image = file
photo.save(touch: false)
end
photo.queue_processing_job
end
end
end

def unzip_photos_file(photo_file_path)
folder = create_folder(photo_file_path)
Zip::File.open(photo_file_path) do |zip_file|
zip_file.each do |file|
target_name = "#{folder}#{Pathname::SEPARATOR_LIST}#{file}"
zip_file.extract(file, target_name) unless File.exist?(target_name)
rescue Errno::ENOENT => e
logger.error e.to_s
end
end
folder
end

def create_folder(compressed_file_name)
extension = File.extname(compressed_file_name)
folder = compressed_file_name.delete_suffix(extension)
FileUtils.mkdir(folder) unless File.exist?(folder)
folder
end

def remove_file_references(user)
user.remove_exported_photos_file
user.remove_export
user.save
end
end
82 changes: 4 additions & 78 deletions app/workers/import_profile.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,90 +9,16 @@ class ImportProfile < Base
def perform(user_id)
user = User.find_by(username: user_id)
if user.nil?
logger.error "A user with name #{user_id} not a local user"
logger.error "A user with name #{user_id} is not a local user"
else
logger.info "Import for profile #{user_id} at path #{user.export.current_path} requested"
import_user_profile(user.export.current_path, user_id)
if user.exported_photos_file&.current_path&.present?
logger.info("Importing photos from import file")
import_user_photos(user)
end
remove_file_references(user)
import_profile.import_by_user(user)
end
end

private

def import_user_profile(path_to_profile, username)
return unless File.exist?(path_to_profile)

service = MigrationService.new(path_to_profile, username)
logger.info "Start validating user profile #{username}"
service.validate
logger.info "Start importing user profile for #{username}"
service.perform!
logger.info "Successfully imported profile: #{username}"
rescue MigrationService::ArchiveValidationFailed => e
logger.error "Errors in the archive found: #{e.message}"
rescue MigrationService::MigrationAlreadyExists
logger.error "Migration record already exists for the user, can't continue"
rescue MigrationService::SelfMigrationNotAllowed
logger.error "You can't migrate onto your own account"
ensure
service&.remove_intermediate_file
end

def import_user_photos(user)
return if user.exported_photos_file&.current_path&.nil?

return unless File.exist?(user.exported_photos_file.current_path)

unzip_photos_file(user.exported_photos_file.current_path)
source_dir = folder_from_filename(user.exported_photos_file.current_path)
user.posts.find_in_batches do |posts|
import_photos_for_posts(posts, source_dir)
end
end

def import_photos_for_posts(posts, source_dir)
posts.each do |post|
post.photos.each do |photo|
uploaded_file = "#{source_dir}/#{photo.remote_photo_name}"
next unless File.exist?(uploaded_file) && photo.remote_photo_name.present?

File.open(uploaded_file) do |file|
photo.random_string = File.basename(uploaded_file, ".*")
photo.unprocessed_image = file
photo.save(touch: false)
end
photo.queue_processing_job
end
end
end

def unzip_photos_file(photo_file_path)
folder = folder_from_filename(photo_file_path)
FileUtils.mkdir(folder) unless File.exist?(folder)

Zip::File.open(photo_file_path) do |zip_file|
zip_file.each do |file|
target_name = "#{folder}#{Pathname::SEPARATOR_LIST}#{file}"
zip_file.extract(file, target_name) unless File.exist?(target_name)
rescue Errno::ENOENT => e
logger.error e.to_s
end
end
end

def folder_from_filename(filename)
extension = File.extname(filename)
filename.delete_suffix(extension)
end

def remove_file_references(user)
user.remove_exported_photos_file
user.remove_export
user.save
def import_profile
@import_profile ||= ImportProfileService.new
end
end
end
18 changes: 9 additions & 9 deletions lib/archive_importer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ def create_user(attr)
profile_attributes: profile_attributes
}
)
user = User.find_or_build(data)
user.getting_started = false
user.save!
@user = User.find_or_build(data)
@user.getting_started = false
@user.save!
end

private
Expand All @@ -61,14 +61,14 @@ def set_auto_follow_back_aspect
name = archive_hash["user"]["auto_follow_back_aspect"]
return if name.nil?

aspect = user.aspects.find_by(name: name)
user.update(auto_follow_back_aspect: aspect) if aspect
aspect = @user.aspects.find_by(name: name)
@user.update(auto_follow_back_aspect: aspect) if aspect
end

def import_aspects
contact_groups.each do |group|
begin
user.aspects.create!(group.slice("name"))
@user.aspects.create!(group.slice("name"))
rescue ActiveRecord::RecordInvalid => e
logger.warn "#{self}: #{e}"
end
Expand All @@ -94,15 +94,15 @@ def import_blocks

def import_collection(collection, importer_class)
collection.each do |object|
importer_class.new(object, user).import
importer_class.new(object, @user).import
end
end

def import_tag_followings
archive_hash.fetch("user").fetch("followed_tags", []).each do |tag_name|
begin
tag = ActsAsTaggableOn::Tag.find_or_create_by(name: tag_name)
user.tag_followings.create!(tag: tag)
@user.tag_followings.create!(tag: tag)
rescue ActiveRecord::RecordInvalid => e
logger.warn "#{self}: #{e}"
end
Expand All @@ -117,7 +117,7 @@ def import_subscriptions
next
end
begin
user.participations.create!(target: post)
@user.participations.create!(target: post)
rescue ActiveRecord::RecordInvalid => e
logger.warn "#{self}: #{e}"
end
Expand Down
68 changes: 36 additions & 32 deletions lib/tasks/accounts.rake
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,49 @@

namespace :accounts do
desc "Perform migration"
task :migration, %i[archive_path new_user_name] => :environment do |_t, args|
puts "Account migration is requested"
args = %i[archive_path new_user_name].map {|name| [name, args[name]] }.to_h
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
process_arguments(args)

begin
service = MigrationService.new(args[:archive_path], args[:new_user_name])
service.validate
puts "Warnings:\n#{service.warnings.join("\n")}\n-----" if service.warnings.any?
if service.only_import?
puts "Warning: Archive owner is not fetchable. Proceeding with data import, but account migration record "\
"won't be created"
end
print "Do you really want to execute the archive import? Note: this is irreversible! [y/N]: "
next unless $stdin.gets.strip.casecmp?("y")

start_time = Time.now.getlocal
service.perform!
puts service.only_import? ? "Data import complete!" : "Data import and migration complete!"
puts "Migration took #{Time.now.getlocal - start_time} seconds"
rescue MigrationService::ArchiveValidationFailed => exception
puts "Errors in the archive found:\n#{exception.message}\n-----"
rescue MigrationService::MigrationAlreadyExists
puts "Migration record already exists for the user, can't continue"
ensure
service.remove_intermediate_file
start_time = Time.now.getlocal
if args[:new_user_name].present?
import_profile = ImportProfileService.new
import_profile.import_by_files(args[:archive_path], args[:photos_path], args[:new_user_name])
else
puts "Must set a user name and a archive file path or photos file path"
end
puts ""
puts "Migration finished took #{Time.now.getlocal - start_time} seconds. (Photos might still be processed)"
end

def process_arguments(args)
if args[:archive_path].nil?
print "Enter the archive path: "
args[:archive_path] = $stdin.gets.strip
end
if args[:new_user_name].nil?
print "Enter the new user name: "
args[:new_user_name] = $stdin.gets.strip
end
request_archive_parameter(args)
request_photos_parameter(args)
request_username(args)
puts "Archive path: #{args[:archive_path]}"
puts "Photos path: #{args[:photos_path]}"
puts "New username: #{args[:new_user_name]}"
end
end

def request_archive_parameter(args)
return unless args[:archive_path].nil?

print "Enter the archive (.json, .gz, .zip) path: "
args[:archive_path] = $stdin.gets.strip
end

def request_photos_parameter(args)
return unless args[:photos_path].nil?

print "Enter the photos (.zip) path: "
args[:photos_path] = $stdin.gets.strip
end

def request_username(args)
return unless args[:new_user_name].nil?

print "Enter the new user name: "
args[:new_user_name] = $stdin.gets.strip
end
4 changes: 2 additions & 2 deletions spec/integration/migration_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,8 @@ def setup_validation_time_expectations
end

it "uncompresses zip archive" do
zip_ccompressed_file = create_zip_archive
service = MigrationService.new(zip_ccompressed_file, new_username)
zip_compressed_file = create_zip_archive
service = MigrationService.new(zip_compressed_file, new_username)
expect(service.only_import?).to be_truthy
end

Expand Down

0 comments on commit a144219

Please sign in to comment.