Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ gem 'font-awesome-rails', '~> 4.7.0.0'
# Authentication gem
gem "devise", ">= 4.7.1"
# Shared libraries for workflow and explore
gem 'etda_utilities', '~> 0.0'
gem 'etda_utilities', "~> 0.22.0"
# Ldap client
gem 'net-ldap', '~> 0.16.1'
# sftp for lionapth csv imports
Expand Down
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ GEM
rubocop (>= 1)
smart_properties
erubi (1.13.1)
etda_utilities (0.21.0)
etda_utilities (0.22.0)
factory_bot (6.5.1)
activesupport (>= 6.1.0)
factory_bot_rails (6.4.4)
Expand Down Expand Up @@ -566,7 +566,7 @@ DEPENDENCIES
down
ed25519 (~> 1.2.4)
enumerize (~> 2.6.0)
etda_utilities (~> 0.0)
etda_utilities (~> 0.22.0)
factory_bot_rails (~> 6.4.0)
faker (~> 3.5.1)
font-awesome-rails (~> 4.7.0.0)
Expand Down
5 changes: 3 additions & 2 deletions app/models/etda_file_paths.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ def explore_base_path
EXPLORE_BASE_PATH
end

def move_a_file(fid, original_file_location)
# file_class injection options: [FinalSubmissionFile, RemediatedFinalSubmissionFile]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

def move_a_file(fid, original_file_location, file_class:)
error_msg = ''

unless File.exist?(original_file_location)
Expand All @@ -18,7 +19,7 @@ def move_a_file(fid, original_file_location)
return error_msg
end

updated_file = FinalSubmissionFile.find(fid)
updated_file = file_class.find(fid)
# this is calculating the new location based on updated submission and file attributes

new_location = updated_file.full_file_path
Expand Down
2 changes: 1 addition & 1 deletion app/models/final_submission_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def move_file

path_builder = EtdaFilePaths.new
original_file_location = "#{WORKFLOW_BASE_PATH}final_submission_files/#{path_builder.detailed_file_path(id)}#{asset_identifier}"
path_builder.move_a_file(id, original_file_location)
path_builder.move_a_file(id, original_file_location, file_class: self.class)
end

def delete_file
Expand Down
40 changes: 40 additions & 0 deletions app/models/remediated_final_submission_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,47 @@ class RemediatedFinalSubmissionFile < ApplicationRecord
validates :submission_id, :asset, presence: true
validates :asset, virus_free: true

after_save :move_file
before_destroy :delete_file

def class_name
self.class.to_s.underscore.dasherize
end

def current_location
# full file path including file name
full_file_path + asset_identifier
end

def full_file_path
# file path w/o file name
main_file_path + file_detail_path
end

def file_detail_path
# partial unique path built from file id -- ie('/01/01/')
# Note: remediated is true to differentiate paths from original files
EtdaFilePaths.new.detailed_file_path(id, remediated: true)
end

def main_file_path
# base portion of path up to file_detail_path
SubmissionFilePath.new(submission).full_path_for_final_submissions.to_s
end

private

def move_file
return unless submission.status_behavior.released_for_publication?

path_builder = EtdaFilePaths.new
original_file_location = "#{WORKFLOW_BASE_PATH}final_submission_files/#{path_builder.detailed_file_path(id, remediated: true)}#{asset_identifier}"
path_builder.move_a_file(id, original_file_location, file_class: self.class)
end

def delete_file
return unless submission.status_behavior.released_for_publication?

FileUtils.rm current_location
end
end
22 changes: 16 additions & 6 deletions app/services/submission_release_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,28 @@ def unpublish(original_final_files)
end

def final_files_for_submission(submission)
# saves the file id and the original file path
# saves the file id, the original file path, and the class name
location_array = []
submission.final_submission_files.each do |f|
location_array << [f.id, f.current_location]
location_array << [f.id, f.current_location, f.class.name]

# also include remediated final submission files to be moved
next if f.remediated_final_submission_file.blank?

location_array << [f.remediated_final_submission_file.id,
f.remediated_final_submission_file.current_location,
f.remediated_final_submission_file.class.name]
end

location_array
end

def release_files(original_file_locations)
etda_file_util = EtdaFilePaths.new
original_file_locations.each do |fid, original_file_location|
msg = etda_file_util.move_a_file(fid, original_file_location)
original_file_locations.each do |fid, original_file_location, class_name|
msg = etda_file_util.move_a_file(fid,
original_file_location,
file_class: class_name.constantize)
next if msg.blank?

record_error(msg)
Expand All @@ -53,10 +63,10 @@ def release_files(original_file_locations)

def file_verification(original_files_array)
file_error_list = []
original_files_array.each do |id, original_file|
original_files_array.each do |id, original_file, class_name|
next if File.exist? original_file

err = "File Not Found for Final Submission File #{id}, #{original_file} "
err = "File Not Found for #{class_name.underscore.humanize} #{id}, #{original_file} "
record_error(err)
file_error_list << err
end
Expand Down
15 changes: 10 additions & 5 deletions app/uploaders/submission_file_uploader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,20 @@ def cache_dir
end

def asset_prefix
case model.class_name
when 'final-submission-file'
case model_class_name
when 'final-submission-file', 'remediated-final-submission-file'
Rails.root.join(WORKFLOW_BASE_PATH, 'final_submission_files')
when 'admin-feedback-file'
Rails.root.join(WORKFLOW_BASE_PATH, 'admin_feedback_files')
when 'remediated_final_submission_files'
Rails.root.join(WORKFLOW_BASE_PATH, 'remediated_final_submission_files')
else
Rails.root.join(WORKFLOW_BASE_PATH, 'format_review_files')
end
end

def asset_hash
path_builder = EtdaFilePaths.new
path_builder.detailed_file_path(model.id)
path_builder.detailed_file_path(model.id,
remediated: model_class_name == 'remediated-final-submission-file')
end

def identity_subdir
Expand All @@ -65,4 +64,10 @@ def content_type_allowlist
def extension_allowlist
%w[pdf txt jpg jpeg png gif mp3 wav mov mp4 zip]
end

private

def model_class_name
model.class_name
end
end
5 changes: 3 additions & 2 deletions spec/models/access_level_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@

describe '#ACCESS_LEVEL_KEYS' do
it 'constant containing all access levels' do
expect(described_class::ACCESS_LEVEL_KEYS).to contain_exactly('open_access', 'restricted_to_institution', 'restricted', '')
expect(described_class::ACCESS_LEVEL_KEYS).to contain_exactly('open_access', 'restricted_to_institution', 'restricted_liberal_arts', 'restricted', '')
expect(described_class::ACCESS_LEVEL_KEYS).to include('open_access')
expect(described_class::ACCESS_LEVEL_KEYS).to include('restricted')
expect(described_class::ACCESS_LEVEL_KEYS).to include('restricted_to_institution')
expect(described_class::ACCESS_LEVEL_KEYS).to include('restricted_liberal_arts')
expect(described_class::ACCESS_LEVEL_KEYS).to include('')
expect(described_class::ACCESS_LEVEL_KEYS.length).to eq(4)
expect(described_class::ACCESS_LEVEL_KEYS.length).to eq(5)
end
end

Expand Down
57 changes: 57 additions & 0 deletions spec/models/etda_file_paths_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,61 @@
expect(described_class.new.explore_open).to eql("#{explore_path}open_access/")
end
end

describe '#move_a_file' do
let(:file_paths) { described_class.new }
let(:fid) { 123 }
let(:original_file_location) { '/tmp/original/file.pdf' }
let(:updated_file) do
instance_double('FinalSubmissionFile',
full_file_path: '/dest/path/',
asset_identifier: 'file.pdf')
end

context 'when the original file does not exist' do
it 'returns an error message and does not look up the file' do
allow(File).to receive(:exist?).with(original_file_location).and_return(false)
allow(Rails.logger).to receive(:error)
file_class = class_double('FinalSubmissionFile')
allow(file_class).to receive(:find)

result = file_paths.move_a_file(fid, original_file_location, file_class: file_class)

expect(result).to eq("File not found: #{original_file_location}")
expect(file_class).not_to have_received(:find)
end
end

context 'when the original file exists' do
it 'moves the file using the provided file_class' do
file_class = class_double('RemediatedFinalSubmissionFile').as_stubbed_const

allow(File).to receive(:exist?).with(original_file_location).and_return(true)
allow(file_class).to receive(:find).with(fid).and_return(updated_file)
allow(FileUtils).to receive(:mkpath)
allow(FileUtils).to receive(:mv)

result = file_paths.move_a_file(fid, original_file_location, file_class: file_class)

expect(FileUtils).to have_received(:mkpath).with('/dest/path/')
expect(FileUtils).to have_received(:mv).with(original_file_location, '/dest/path/file.pdf')
expect(result).to eq('')
end
end

context 'when using FinalSubmissionFile as the file_class' do
it 'uses FinalSubmissionFile to find the record' do
file_class = class_double('FinalSubmissionFile').as_stubbed_const

allow(File).to receive(:exist?).with(original_file_location).and_return(true)
allow(file_class).to receive(:find).with(fid).and_return(updated_file)
allow(FileUtils).to receive(:mkpath)
allow(FileUtils).to receive(:mv)

file_paths.move_a_file(fid, original_file_location, file_class: file_class)

expect(file_class).to have_received(:find).with(fid)
end
end
end
end
83 changes: 83 additions & 0 deletions spec/models/remediated_final_submission_file_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,38 @@
expect(described_class.new.class_name).to eql('remediated-final-submission-file')
end

describe '#current_location' do
context 'when submission is waiting for publication release' do
it 'returns full workflow file path w filename' do
submission = FactoryBot.create :submission, :waiting_for_publication_release
remediated_final_submission_file = FactoryBot.create(:remediated_final_submission_file,
submission_id: submission.id)
remediated_final_submission_file.id = 1234
expect(remediated_final_submission_file.current_location)
.to eq(
"#{WORKFLOW_BASE_PATH}final_submission_files/" \
"#{EtdaFilePaths.new.detailed_file_path(remediated_final_submission_file.id, remediated: true)}" \
"#{remediated_final_submission_file.asset_identifier}"
)
end
end

context 'when submission has been released for publication' do
it 'returns full explore file path w filename' do
submission = FactoryBot.create :submission, :released_for_publication
remediated_final_submission_file = FactoryBot.create(:remediated_final_submission_file,
submission_id: submission.id)
remediated_final_submission_file.id = 1234
expect(remediated_final_submission_file.current_location)
.to eq(
"#{EXPLORE_BASE_PATH + submission.access_level_key}" \
"/#{EtdaFilePaths.new.detailed_file_path(remediated_final_submission_file.id, remediated: true)}" \
"#{remediated_final_submission_file.asset_identifier}"
)
end
end
end

describe 'virus scanning' do
# We have these Virus scanner tests for both format review file and final_submission_file models
# Not sure if it's valauble to have them here as well?
Expand Down Expand Up @@ -60,4 +92,55 @@
end
end
end

describe 'after_save :move_file' do
let(:submission) do
FactoryBot.create :submission,
:released_for_publication
end

let(:remediated_file) do
FactoryBot.create :remediated_final_submission_file,
submission: submission
end

it 'calls EtdaFilePaths.move_a_file with remediated_file: true' do
path_builder = instance_double(EtdaFilePaths)
allow(EtdaFilePaths).to receive(:new).and_return(path_builder)
allow(path_builder).to receive(:detailed_file_path).and_return('path/to/file/')
allow(path_builder).to receive(:move_a_file)

original_file_location = "#{WORKFLOW_BASE_PATH}final_submission_files/" \
"#{path_builder.detailed_file_path(remediated_file.id, remediated: true)}" \
"#{remediated_file.asset_identifier}"

remediated_file.save!

# Expect twice: once during create, once during save!
expect(path_builder)
.to have_received(:move_a_file)
.with(remediated_file.id, original_file_location, file_class: remediated_file.class)
.twice
end
end

describe 'before_destroy :delete_file' do
let(:submission) do
FactoryBot.create :submission,
:released_for_publication
end

let(:remediated_file) do
FactoryBot.create :remediated_final_submission_file,
submission: submission
end

it 'deletes the file from the filesystem' do
expect(File.exist?(remediated_file.current_location)).to be true

remediated_file.destroy

expect(File.exist?(remediated_file.current_location)).to be false
end
end
end
Loading