diff --git a/app/concepts/project/operation/create_remix.rb b/app/concepts/project/operation/create_remix.rb index ac4cfdeb5..42cea7ac2 100644 --- a/app/concepts/project/operation/create_remix.rb +++ b/app/concepts/project/operation/create_remix.rb @@ -36,6 +36,10 @@ def create_remix(original_project, params, user_id) proj.remixed_from_id = original_project.id end + original_project.images.each do |image| + remix.images.attach(image.blob) + end + params[:components].each do |x| remix.components.build(x.slice(:name, :extension, :content, :index)) end diff --git a/lib/tasks/projects.rake b/lib/tasks/projects.rake index 1c8d61fb1..241b841ff 100644 --- a/lib/tasks/projects.rake +++ b/lib/tasks/projects.rake @@ -21,9 +21,9 @@ namespace :projects do end project_images = proj_config['IMAGES'] || [] + delete_removed_images(project, project_images) project_images.each do |image_name| - project.images.attach(io: File.open(File.dirname(__FILE__) + "/project_components/#{dir}/#{image_name}"), - filename: image_name) + attach_image_if_needed(project, image_name, dir) end project.save @@ -38,8 +38,41 @@ def find_project(proj_config) project = Project.find_by(identifier: proj_config['IDENTIFIER']) project.name = proj_config['NAME'] project.components.each(&:destroy) - project.images.purge end project end + +def delete_removed_images(project, images_to_attach) + existing_images = project.images.map { |x| x.blob.filename.to_s } + diff = existing_images - images_to_attach + return if diff.empty? + + diff.each do |filename| + img = project.images.find { |i| i.blob.filename == filename } + img.purge + end +end + +def attach_image_if_needed(project, image_name, dir) + existing_image = project.images.find { |i| i.blob.filename == image_name } + + if existing_image + return if existing_image.blob.checksum == image_checksum(image_name, dir) + + existing_image.purge + end + project.images.attach(io: File.open(File.dirname(__FILE__) + "/project_components/#{dir}/#{image_name}"), + filename: image_name) +end + +def image_checksum(image_name, dir) + io = File.open(File.dirname(__FILE__) + "/project_components/#{dir}/#{image_name}") + OpenSSL::Digest.new('MD5').tap do |checksum| + while (chunk = io.read(5.megabytes)) + checksum << chunk + end + + io.rewind + end.base64digest +end diff --git a/spec/concepts/project/operation/create_remix_spec.rb b/spec/concepts/project/operation/create_remix_spec.rb index 4bc05f711..07e74d268 100644 --- a/spec/concepts/project/operation/create_remix_spec.rb +++ b/spec/concepts/project/operation/create_remix_spec.rb @@ -6,7 +6,7 @@ subject(:create_remix) { described_class.call(params: remix_params, user_id: user_id, original_project: original_project) } let(:user_id) { 'e0675b6c-dc48-4cd6-8c04-0f7ac05af51a' } - let!(:original_project) { create(:project, :with_components) } + let!(:original_project) { create(:project, :with_components, :with_attached_image) } let(:remix_params) do component = original_project.components.first { @@ -59,6 +59,19 @@ expect(remixed_attrs).to eq(original_attrs) end + it 'links remix to attached images' do + remixed_project = create_remix[:project] + expect(remixed_project.images.length).to eq(original_project.images.length) + end + + it 'creates a new attachment' do + expect { create_remix }.to change(ActiveStorage::Attachment, :count).by(1) + end + + it 'does not create a new image' do + expect { create_remix }.not_to change(ActiveStorage::Blob, :count) + end + it 'creates new components' do expect { create_remix }.to change(Component, :count).by(1) end diff --git a/spec/factories/project.rb b/spec/factories/project.rb index 590f4adbf..d3551c11f 100644 --- a/spec/factories/project.rb +++ b/spec/factories/project.rb @@ -25,9 +25,11 @@ end end - trait :with_attached_images do - after(:create) do |object| - object.images.attach(fixture_file_upload(Rails.root.join('spec/fixtures/test_image_1.png'), 'image/png')) + trait :with_attached_image do + after(:build) do |object| + object.images.attach(io: File.open(Rails.root.join('spec/fixtures/files/test_image_1.png')), + filename: 'test_image', + content_type: 'image/png') end end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index a1a4b53a2..a6a4e2161 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -8,6 +8,10 @@ it { is_expected.to have_many(:children) } it { is_expected.to belong_to(:parent).optional(true) } it { is_expected.to have_many_attached(:images) } + + it 'purges attached images' do + expect(described_class.reflect_on_attachment(:images).options[:dependent]).to eq(:purge_later) + end end describe 'identifier not nil' do