diff --git a/README.md b/README.md
index 060f25f..90a65a8 100644
--- a/README.md
+++ b/README.md
@@ -17,11 +17,11 @@ Its primary job is to manage the flow of content from Fedora into Swift for pres
## Workflow
-1. Any save (create or update) on a GenericFile in ERA will trigger an after save callback that will push the GenericFile unique identifier (NOID) into a Queue.
-2. The queue (Redis) is setup to be a unique set (which only allows one GenericFile NOID to be included in the queue at a single time), and ordered by priority from First In, First out (FIFO).
+1. Any save (create or update) on a Item/Thesis in ERA/Jupiter will trigger an after save callback that will push the item's unique identifier (UUID or NOID) into a Queue.
+2. The queue (Redis) is setup to be a unique set (which only allows one item's UUID to be included in the queue at a single time), and ordered by priority from First In, First out (FIFO).
3. PushmiPullyu will then monitor the queue. After a certain wait period has passed since an element has been on the queue, PushmiPullyu will then retrieve the elements off the queue and begin to process the preservation event.
-4. All the GenericFile information and data required for preservation are retrieved from Fedora and Solr using multiple REST calls.
-5. An Archival Information Package (AIP) is created from the GenericFile's information. It is then bagged and tarred.
+4. All the GenericFile information and data required for preservation are retrieved from Fedora using multiple REST calls. A database connection to the user database fetches (via ActiveRecord )owner emails and modifies the fetched documents, where applicable.
+5. An Archival Information Package (AIP) is created from the item's information. It is then bagged and tarred.
6. The AIP tar is then uploaded to Swift via a REST call.
7. On a successful Swift upload, a entry is added for this preservation event to the preservation event logs.
diff --git a/docs/images/system-infrastructure-diagram.png b/docs/images/system-infrastructure-diagram.png
index f1f71a6..9a9d571 100644
Binary files a/docs/images/system-infrastructure-diagram.png and b/docs/images/system-infrastructure-diagram.png differ
diff --git a/examples/pushmi_pullyu.yml b/examples/pushmi_pullyu.yml
index 44421c7..ed14975 100644
--- a/examples/pushmi_pullyu.yml
+++ b/examples/pushmi_pullyu.yml
@@ -8,6 +8,7 @@
# PushmiPullyu will run this file through ERB when reading it so you can
# even put in dynamic logic, like consuming ENV Variables.
+aip_version: 'lightaip-2.0'
debug: false
logdir: log
monitor: false
@@ -20,15 +21,18 @@ minimum_age: 0
redis:
url: redis://localhost:6379
-solr:
- url: http://localhost:8983/solr/development
-
fedora:
url: http://localhost:8080/fcrepo/rest
user: fedoraAdmin
password: fedoraAdmin
base_path: /dev
+database:
+ encoding: utf8
+ url: postgresql://jupiter:mysecretpassword@127.0.0.1
+ database: jupiter_development
+ pool: 5
+
#parameters project_name and project_domain_name are required only for keystone v3 authentication
swift:
tenant: tester
diff --git a/lib/pushmi_pullyu.rb b/lib/pushmi_pullyu.rb
index 11adf6e..476fee2 100644
--- a/lib/pushmi_pullyu.rb
+++ b/lib/pushmi_pullyu.rb
@@ -8,8 +8,11 @@
require 'pushmi_pullyu/aip'
require 'pushmi_pullyu/aip/creator'
require 'pushmi_pullyu/aip/downloader'
-require 'pushmi_pullyu/aip/solr_fetcher'
require 'pushmi_pullyu/aip/fedora_fetcher'
+require 'pushmi_pullyu/aip/file_list_creator'
+require 'pushmi_pullyu/aip/owner_email_editor'
+require 'active_record'
+require 'pushmi_pullyu/aip/user'
require 'pushmi_pullyu/cli'
require 'pushmi_pullyu/preservation_queue'
require 'pushmi_pullyu/swift_depositer'
@@ -20,6 +23,7 @@
# PushmiPullyu main module
module PushmiPullyu
DEFAULTS = {
+ aip_version: 'lightaip-2.0',
daemonize: false,
debug: false,
logdir: 'log',
@@ -32,10 +36,6 @@ module PushmiPullyu
redis: {
url: 'redis://localhost:6379'
},
- # TODO: rest of these are examples for solr/fedora/swift... feel free to fill them in correctly
- solr: {
- url: 'http://localhost:8983/solr/development'
- },
fedora: {
url: 'http://localhost:8080/fcrepo/rest',
user: 'fedoraAdmin',
@@ -52,6 +52,12 @@ module PushmiPullyu
container: 'ERA'
},
rollbar: {
+ },
+ database: {
+ encoding: 'utf8',
+ pool: ENV['RAILS_MAX_THREADS'] || 5,
+ url: ENV['DATABASE_URL'] || ENV['JUPITER_DATABASE_URL'] || 'postgresql://jupiter:mysecretpassword@127.0.0.1',
+ database: 'jupiter_development'
}
}.freeze
diff --git a/lib/pushmi_pullyu/aip/creator.rb b/lib/pushmi_pullyu/aip/creator.rb
index 284d015..a5d6e52 100644
--- a/lib/pushmi_pullyu/aip/creator.rb
+++ b/lib/pushmi_pullyu/aip/creator.rb
@@ -22,11 +22,15 @@ def run
private
def bag_aip
- bag = BagIt::Bag.new(@aip_directory)
+ bag = BagIt::Bag.new(@aip_directory, bag_metadata)
bag.manifest!
raise BagInvalid unless bag.valid?
end
+ def bag_metadata
+ { 'AIP-Version' => PushmiPullyu.options[:aip_version] }
+ end
+
def tar_bag
# We want to change the directory to the work directory path so we get the tar file to be exactly
# the contents of the noid directory and not the entire work directory structure. For example the noid.tar
diff --git a/lib/pushmi_pullyu/aip/downloader.rb b/lib/pushmi_pullyu/aip/downloader.rb
index 8f5d3d3..a0b4f2e 100644
--- a/lib/pushmi_pullyu/aip/downloader.rb
+++ b/lib/pushmi_pullyu/aip/downloader.rb
@@ -7,7 +7,18 @@
# related to an object
class PushmiPullyu::AIP::Downloader
+ PREDICATE_URIS = {
+ filename: 'http://purl.org/dc/terms/title',
+ member_files: 'http://pcdm.org/models#hasFile',
+ member_file_sets: 'http://pcdm.org/models#hasMember',
+ original_file: 'http://pcdm.org/use#OriginalFile',
+ type: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'
+ }.freeze
+
+ class NoFileSets < StandardError; end
+ class NoMemberFiles < StandardError; end
class NoContentFilename < StandardError; end
+ class NoOriginalFile < StandardError; end
def initialize(noid, aip_directory)
@noid = noid
@@ -19,21 +30,45 @@ def run
PushmiPullyu.logger.info("#{@noid}: Retreiving data from Fedora ...")
- [:main_object, :fixity, :content_datastream_metadata, :versions, :thumbnail,
- :characterization, :fedora3foxml, :fedora3foxml_metadata].each do |item|
- path_spec = aip_paths[item]
- download_and_log(path_spec, PushmiPullyu::AIP::FedoraFetcher.new(@noid))
- end
+ # Main object metadata
+ object_downloader = PushmiPullyu::AIP::FedoraFetcher.new(@noid)
+ download_and_log(object_aip_paths[:main_object], object_downloader)
- # Need content filename from metadata
- path_spec = OpenStruct.new(
- remote: '/content',
- local: content_filename, # lookup filename derived from metadata
- optional: false
- )
- download_and_log(path_spec, PushmiPullyu::AIP::FedoraFetcher.new(@noid))
+ # Construct the file ordering file
+ list_source_uri = object_downloader.object_url + object_aip_paths.list_source.remote
+ create_and_log_file_order_list(list_source_uri)
+
+ member_file_set_uuids.each do |file_set_uuid|
+ make_file_set_directories(file_set_uuid)
+
+ # FileSet metadata
+ file_set_downloader = PushmiPullyu::AIP::FedoraFetcher.new(file_set_uuid)
+ path_spec = file_set_aip_paths(file_set_uuid)[:main_object]
+ download_and_log(path_spec, file_set_downloader)
+
+ # Find the original file by looping through the files in the file_set
+ original_file_remote_base = nil
+ member_files(file_set_uuid).each do |file_path|
+ path_spec = OpenStruct.new(
+ remote: "/files/#{file_path}/fcr:metadata",
+ # Note: local file gets clobbered on each download until it finds the right one
+ local: "#{file_set_dirs(file_set_uuid).metadata}/original_file_metadata.n3",
+ optional: true
+ )
+ download_and_log(path_spec, file_set_downloader)
+ if original_file?(path_spec.local)
+ original_file_remote_base = "/files/#{file_path}"
+ break
+ end
+ end
- download_permissions
+ raise NoOriginalFile unless original_file_remote_base.present?
+
+ [:content, :fixity].each do |item|
+ path_spec = file_aip_paths(file_set_uuid, original_file_remote_base)[item]
+ download_and_log(path_spec, file_set_downloader)
+ end
+ end
end
private
@@ -43,35 +78,24 @@ def download_and_log(path_spec, fedora_fetcher)
log_fetching(fedora_fetcher.object_url(path_spec.remote), output_file)
- is_rdf = (output_file !~ /\.n3$/)
+ is_rdf = (output_file =~ /\.n3$/)
+ should_add_user_email = path_spec.to_h.fetch(:should_add_user_email, false)
is_success = fedora_fetcher.download_object(output_file,
url_extra: path_spec.remote,
optional: path_spec.optional,
- is_rdf: is_rdf)
+ is_rdf: is_rdf,
+ should_add_user_email: should_add_user_email)
log_saved(is_success, output_file)
end
- def download_permissions
- PushmiPullyu.logger.info("#{@noid}: looking up permissions from Solr ...")
- results = PushmiPullyu::AIP::SolrFetcher.new(@noid).fetch_permission_object_ids
- if results.empty?
- PushmiPullyu.logger.info("#{@noid}: permissions not found")
- else
- results.each do |permission_id|
- PushmiPullyu.logger.info("#{@noid}: permission object #{permission_id} found")
- download_permission(permission_id)
- end
- end
- end
-
- def download_permission(permission_id)
- path_spec = OpenStruct.new(
- remote: nil,
- local: "#{aip_dirs.metadata}/permission_#{permission_id}.n3",
- optional: false
- )
- download_and_log(path_spec, PushmiPullyu::AIP::FedoraFetcher.new(permission_id))
+ def create_and_log_file_order_list(url)
+ output_file = object_aip_paths.file_ordering.local
+ PushmiPullyu::Logging.log_aip_activity(@aip_directory,
+ "#{@noid}: #{output_file} -- creating from #{url} ...")
+ PushmiPullyu::AIP::FileListCreator.new(url, output_file, member_file_set_uuids).run
+ PushmiPullyu::Logging.log_aip_activity(@aip_directory,
+ "#{@noid}: #{output_file} -- created")
end
### Logging
@@ -92,8 +116,19 @@ def aip_dirs
@aip_dirs ||= OpenStruct.new(
objects: "#{@aip_directory}/data/objects",
metadata: "#{@aip_directory}/data/objects/metadata",
+ files: "#{@aip_directory}/data/objects/files",
+ files_metadata: "#{@aip_directory}/data/objects/metadata/files_metadata",
logs: "#{@aip_directory}/data/logs",
- thumbnails: "#{@aip_directory}/data/thumbnails"
+ file_logs: "#{@aip_directory}/data/logs/files_logs"
+ )
+ end
+
+ def file_set_dirs(file_set_uuid)
+ @file_set_dirs ||= {}
+ @file_set_dirs[file_set_uuid] ||= OpenStruct.new(
+ metadata: "#{aip_dirs.files_metadata}/#{file_set_uuid}",
+ files: "#{aip_dirs.files}/#{file_set_uuid}",
+ logs: "#{aip_dirs.file_logs}/#{file_set_uuid}"
)
end
@@ -106,6 +141,14 @@ def make_directories
PushmiPullyu.logger.debug("#{@noid}: Creating directories done")
end
+ def make_file_set_directories(file_set_uuid)
+ PushmiPullyu.logger.debug("#{@noid}: Creating file set #{file_set_uuid} directories ...")
+ file_set_dirs(file_set_uuid).to_h.each_value do |path|
+ FileUtils.mkdir_p(path)
+ end
+ PushmiPullyu.logger.debug("#{@noid}: Creating file set #{file_set_uuid} directories done")
+ end
+
def clean_directories
return unless File.exist?(@aip_directory)
PushmiPullyu.logger.debug("#{@noid}: Nuking directories ...")
@@ -114,63 +157,105 @@ def clean_directories
### Files
- def aip_paths
- @aip_paths ||= OpenStruct.new(
+ def object_aip_paths
+ @object_aip_paths ||= OpenStruct.new(
main_object: OpenStruct.new(
remote: nil, # Base path
local: "#{aip_dirs.metadata}/object_metadata.n3",
+ should_add_user_email: true,
optional: false
),
- fixity: OpenStruct.new(
- remote: '/content/fcr:fixity',
- local: "#{aip_dirs.logs}/content_fixity_report.n3",
- optional: false
+ list_source: OpenStruct.new(
+ # This is downloaded, but not saved
+ remote: '/list_source'
),
- content_datastream_metadata: OpenStruct.new(
- remote: '/content/fcr:metadata',
- local: "#{aip_dirs.metadata}/content_fcr_metadata.n3",
+ # This is constructed, not downloaded
+ file_ordering: OpenStruct.new(
+ local: "#{aip_dirs.files_metadata}/file_order.xml"
+ )
+ ).freeze
+ end
+
+ def file_set_aip_paths(file_set_uuid)
+ @file_set_aip_paths ||= {}
+ @file_set_aip_paths[file_set_uuid] ||= OpenStruct.new(
+ main_object: OpenStruct.new(
+ remote: nil, # Base file_set path
+ local: "#{file_set_dirs(file_set_uuid).metadata}/file_set_metadata.n3",
+ should_add_user_email: true,
optional: false
- ),
- versions: OpenStruct.new(
- remote: '/content/fcr:versions',
- local: "#{aip_dirs.metadata}/content_versions.n3",
+ )
+ ).freeze
+ end
+
+ def file_aip_paths(file_set_uuid, original_file_remote_base)
+ @file_aip_paths ||= {}
+ @file_aip_paths[file_set_uuid] ||= OpenStruct.new(
+ content: OpenStruct.new(
+ remote: original_file_remote_base,
+ local: file_set_filename(file_set_uuid),
optional: false
),
- # Optional downloads
- thumbnail: OpenStruct.new(
- remote: '/thumbnail',
- local: "#{aip_dirs.thumbnails}/thumbnail",
- optional: true
- ),
- characterization: OpenStruct.new(
- remote: '/characterization',
- local: "#{aip_dirs.logs}/content_characterization.n3",
- optional: true
- ),
- fedora3foxml: OpenStruct.new(
- remote: '/fedora3foxml',
- local: "#{aip_dirs.metadata}/fedora3foxml.xml",
- optional: true
- ),
- fedora3foxml_metadata: OpenStruct.new(
- remote: '/fedora3foxml/fcr:metadata',
- local: "#{aip_dirs.metadata}/fedora3foxml.n3",
- optional: true
+ fixity: OpenStruct.new(
+ remote: "#{original_file_remote_base}/fcr:fixity",
+ local: "#{file_set_dirs(file_set_uuid)[:logs]}/content_fixity_report.n3",
+ optional: false
)
).freeze
end
- # Extract filename from main object metadata
- def content_filename
- filename_predicate = RDF::URI('info:fedora/fedora-system:def/model#downloadFilename')
+ def member_file_set_uuids
+ @member_file_set_uuids ||= []
+ return @member_file_set_uuids unless @member_file_set_uuids.empty?
- graph = RDF::Graph.load(aip_paths.main_object.local)
+ member_file_set_predicate = RDF::URI(PREDICATE_URIS[:member_file_sets])
+
+ graph = RDF::Graph.load(object_aip_paths.main_object.local)
+
+ graph.query(predicate: member_file_set_predicate) do |results|
+ # Get uuid from end of fedora path
+ @member_file_set_uuids << results.object.to_s.split('/').last
+ end
+ return @member_file_set_uuids unless @member_file_set_uuids.empty?
+
+ raise NoFileSets
+ end
+
+ def file_set_filename(file_set_uuid)
+ filename_predicate = RDF::URI(PREDICATE_URIS[:filename])
+
+ graph = RDF::Graph.load(file_set_aip_paths(file_set_uuid).main_object.local)
graph.query(predicate: filename_predicate) do |results|
- return "#{aip_dirs.objects}/#{results.object}"
+ return "#{file_set_dirs(file_set_uuid).files}/#{results.object}"
end
raise NoContentFilename
end
+ def member_files(file_set_uuid)
+ member_file_predicate = RDF::URI(PREDICATE_URIS[:member_files])
+
+ graph = RDF::Graph.load(file_set_aip_paths(file_set_uuid).main_object.local)
+
+ member_files = []
+ graph.query(predicate: member_file_predicate) do |results|
+ # Get uuid from end of fedora path
+ member_files << results.object.to_s.split('/').last
+ end
+ return member_files if member_files.present?
+
+ raise NoMemberFiles
+ end
+
+ def original_file?(metadata_filename)
+ type_predicate = RDF::URI(PREDICATE_URIS[:type])
+ original_file_uri = RDF::URI(PREDICATE_URIS[:original_file])
+ graph = RDF::Graph.load(metadata_filename)
+ graph.query(predicate: type_predicate) do |results|
+ return true if results.object == original_file_uri
+ end
+ false
+ end
+
end
diff --git a/lib/pushmi_pullyu/aip/fedora_fetcher.rb b/lib/pushmi_pullyu/aip/fedora_fetcher.rb
index 0b194c5..b34d8df 100644
--- a/lib/pushmi_pullyu/aip/fedora_fetcher.rb
+++ b/lib/pushmi_pullyu/aip/fedora_fetcher.rb
@@ -19,7 +19,8 @@ def object_url(url_extra = nil)
# Return true on success, raise an error otherwise
# (or use 'optional' to return false on 404)
def download_object(download_path, url_extra: nil,
- optional: false, is_rdf: false)
+ optional: false, is_rdf: false,
+ should_add_user_email: false)
uri = URI(object_url(url_extra))
@@ -34,8 +35,13 @@ def download_object(download_path, url_extra: nil,
end
if response.is_a?(Net::HTTPSuccess)
+ body = if should_add_user_email
+ PushmiPullyu::AIP::OwnerEmailEditor.new(response.body).run
+ else
+ response.body
+ end
file = File.open(download_path, 'wb')
- file.write(response.body)
+ file.write(body)
file.close
return true
elsif response.is_a?(Net::HTTPNotFound)
diff --git a/lib/pushmi_pullyu/aip/file_list_creator.rb b/lib/pushmi_pullyu/aip/file_list_creator.rb
new file mode 100644
index 0000000..b418a23
--- /dev/null
+++ b/lib/pushmi_pullyu/aip/file_list_creator.rb
@@ -0,0 +1,115 @@
+require 'rdf'
+require 'rdf/n3'
+
+class PushmiPullyu::AIP::FileListCreator
+
+ IANA = 'http://www.iana.org/assignments/relation/'.freeze
+ PREDICATES = {
+ proxy_for: RDF::URI('http://www.openarchives.org/ore/terms/proxyFor'),
+ first: RDF::URI(IANA + 'first'),
+ last: RDF::URI(IANA + 'last'),
+ prev: RDF::URI(IANA + 'prev'),
+ next: RDF::URI(IANA + 'next'),
+ has_part: RDF::URI('http://purl.org/dc/terms/hasPart')
+ }.freeze
+
+ class NoProxyURIFound < StandardError; end
+ class NoFirstProxyFound < StandardError; end
+ class FirstProxyHasPrev < StandardError; end
+ class ListSourceFileSetMismatch < StandardError; end
+
+ def initialize(list_source_uri, output_xml_file, file_set_uuids)
+ @uri = RDF::URI(list_source_uri)
+ @output_file = output_xml_file
+
+ # These are the known fileset uuids, used for validation
+ @file_set_uuids = file_set_uuids
+ end
+
+ def run
+ extract_list_source_uuids
+ raise ListSourceFileSetMismatch, @uri.to_s if @list_source_uuids.sort != @file_set_uuids.sort
+
+ write_output_file
+ end
+
+ def extract_list_source_uuids
+ # Note: raises IOError if can't find
+ # raises RDF::ReaderError if can't parse
+ @graph = RDF::Graph.load(@uri, validate: true)
+
+ @list_source_uuids = []
+
+ # Fetch first FileSet in list source
+ this_proxy = find_first_proxy
+
+ while @list_source_uuids.count <= num_proxies
+ @list_source_uuids << uuid_from_proxy(this_proxy)
+ next_proxy = find_next_proxy(this_proxy)
+
+ break if next_proxy.nil?
+
+ raise NextPreviousProxyMismatch if this_proxy != find_prev_proxy(next_proxy)
+ this_proxy = next_proxy
+ end
+
+ raise ProxyCountIncorrect if @list_source_uuids.count != num_proxies
+ raise LastProxyFailsValidation if this_proxy != find_last_proxy
+ end
+
+ def num_proxies
+ @num_proxies ||= @graph.query(subject: @uri, predicate: PREDICATES[:has_part]).count
+ end
+
+ def uuid_from_proxy(proxy_uri)
+ @graph.query(subject: proxy_uri, predicate: PREDICATES[:proxy_for]) do |statement|
+ return statement.object.to_s.split('/').last
+ end
+ raise NoProxyURIFound, proxy_uri.to_s
+ end
+
+ def find_first_proxy
+ @graph.query(subject: @uri, predicate: PREDICATES[:first]) do |statement|
+ first_uri = statement.object
+ # Validate that the first proxy doesn't have a previous one
+ raise FirstProxyHasPrev, @uri.to_s if find_prev_proxy(first_uri)
+ return first_uri
+ end
+ raise NoFirstProxyFound, @uri.to_s
+ end
+
+ def find_last_proxy
+ @graph.query(subject: @uri, predicate: PREDICATES[:last]) do |statement|
+ last_uri = statement.object
+ # Validate that the last proxy doesn't have a next one
+ raise LastProxyHasNext, @uri.to_s if find_next_proxy(last_uri)
+ return last_uri
+ end
+ raise LastProxyFound, @uri.to_s
+ end
+
+ def find_next_proxy(proxy_uri)
+ @graph.query(subject: proxy_uri, predicate: PREDICATES[:next]) do |statement|
+ return statement.object
+ end
+ nil
+ end
+
+ def find_prev_proxy(proxy_uri)
+ @graph.query(subject: proxy_uri, predicate: PREDICATES[:prev]) do |statement|
+ return statement.object
+ end
+ nil
+ end
+
+ def write_output_file
+ File.open(@output_file, 'w') do |file|
+ file.write("\n")
+ @list_source_uuids.each do |uuid|
+ file.write(" #{uuid}\n")
+ end
+ file.write("\n")
+ end
+ end
+
+end
diff --git a/lib/pushmi_pullyu/aip/owner_email_editor.rb b/lib/pushmi_pullyu/aip/owner_email_editor.rb
new file mode 100644
index 0000000..c2204cf
--- /dev/null
+++ b/lib/pushmi_pullyu/aip/owner_email_editor.rb
@@ -0,0 +1,62 @@
+require 'net/http'
+
+class PushmiPullyu::AIP::OwnerEmailEditor
+
+ OWNER_PREDICATE = RDF::URI('http://purl.org/ontology/bibo/owner').freeze
+
+ class NoOwnerPredicate < StandardError; end
+
+ def initialize(rdf_string)
+ @document = rdf_string
+ end
+
+ def run
+ ensure_database_connection
+
+ is_modified = false
+ prefixes = nil
+ # Read once to load prefixes (the @things at the top of an n3 file)
+ RDF::N3::Reader.new(input = @document) do |reader|
+ reader.each_statement { |_statement| }
+ prefixes = reader.prefixes
+ end
+ new_body = RDF::N3::Writer.buffer(prefixes: prefixes) do |writer|
+ RDF::N3::Reader.new(input = @document) do |reader|
+ reader.each_statement do |statement|
+ if statement.predicate == OWNER_PREDICATE
+ user = PushmiPullyu::AIP::User.find(statement.object.to_i)
+ writer << [statement.subject, statement.predicate, user.email]
+ is_modified = true
+ else
+ writer << statement
+ end
+ end
+ end
+ end
+ return new_body if is_modified
+ raise NoOwnerPredicate
+ end
+
+ private
+
+ def ensure_database_connection
+ return if ActiveRecord::Base.connected?
+ ActiveRecord::Base.establish_connection(database_configuration)
+ end
+
+ def database_configuration
+ # Config either from URL, or with more granular options (the later taking precedence)
+ config = {}
+ uri = URI.parse(PushmiPullyu.options[:database][:url])
+ config[:adapter] = PushmiPullyu.options[:database][:adaptor] || uri.scheme
+ config[:host] = PushmiPullyu.options[:database][:host] || uri.host
+ config[:database] = PushmiPullyu.options[:database][:database] || uri.path.split('/')[1].to_s
+ config[:username] = PushmiPullyu.options[:database][:username] || uri.user
+ config[:password] = PushmiPullyu.options[:database][:password] || uri.password
+ params = CGI.parse(uri.query || '')
+ config[:encoding] = PushmiPullyu.options[:database][:encoding] || params['encoding'].to_a.first
+ config[:pool] = PushmiPullyu.options[:database][:pool] || params['pool'].to_a.first
+ config
+ end
+
+end
diff --git a/lib/pushmi_pullyu/aip/solr_fetcher.rb b/lib/pushmi_pullyu/aip/solr_fetcher.rb
deleted file mode 100644
index f4b9388..0000000
--- a/lib/pushmi_pullyu/aip/solr_fetcher.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require 'json'
-require 'net/http'
-
-class PushmiPullyu::AIP::SolrFetcher
-
- class SolrFetchError < StandardError; end
-
- def initialize(noid)
- @noid = noid
- end
-
- def fetch_permission_object_ids
- hash = JSON.parse(run_query_json)
-
- return [] if hash['response']['docs'].empty?
-
- hash['response']['docs'].map { |hit| hit['id'] }
- end
-
- private
-
- # Return fetched results, else raise an error
- def run_query_json
- response = Net::HTTP.get_response(
- URI("#{PushmiPullyu.options[:solr][:url]}/select?q=accessTo_ssim:#{@noid}&fl=id&wt=json")
- )
-
- return response.body if response.is_a?(Net::HTTPSuccess)
-
- raise SolrFetchError
- end
-
-end
diff --git a/lib/pushmi_pullyu/aip/user.rb b/lib/pushmi_pullyu/aip/user.rb
new file mode 100644
index 0000000..9d59c4c
--- /dev/null
+++ b/lib/pushmi_pullyu/aip/user.rb
@@ -0,0 +1,2 @@
+class PushmiPullyu::AIP::User < ActiveRecord::Base
+end
diff --git a/pushmi_pullyu.gemspec b/pushmi_pullyu.gemspec
index 489e3b1..61acf0d 100644
--- a/pushmi_pullyu.gemspec
+++ b/pushmi_pullyu.gemspec
@@ -1,4 +1,4 @@
-lib = File.expand_path('../lib', __FILE__)
+lib = File.expand_path('lib', __dir__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'pushmi_pullyu/version'
@@ -21,12 +21,14 @@ Gem::Specification.new do |spec|
spec.required_ruby_version = '>= 2.3.1'
+ spec.add_runtime_dependency 'activerecord', '~> 5.1.5'
spec.add_runtime_dependency 'activesupport', '~> 5.0'
spec.add_runtime_dependency 'bagit', '~> 0.4'
spec.add_runtime_dependency 'connection_pool', '~> 2.2'
spec.add_runtime_dependency 'daemons', '~> 1.2', '>= 1.2.4'
spec.add_runtime_dependency 'minitar', '~> 0.6'
spec.add_runtime_dependency 'openstack', '~> 3.3', '>= 3.3.10'
+ spec.add_runtime_dependency 'pg', '~> 1.0.0'
spec.add_runtime_dependency 'rdf', '>= 1.99', '< 4.0'
spec.add_runtime_dependency 'rdf-n3', '>= 1.99', '< 4.0'
spec.add_runtime_dependency 'redis', '>= 3.3', '< 5.0'
diff --git a/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/logs/aipcreation.log b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/logs/aipcreation.log
new file mode 100644
index 0000000..e20e655
--- /dev/null
+++ b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/logs/aipcreation.log
@@ -0,0 +1,29 @@
+# Logfile created on 2018-03-19 15:25:54 -0600 by logger.rb/56815
+I, [2018-03-19T15:25:54.849868 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/object_metadata.n3 -- fetching from http://localhost:8080/fcrepo/rest/dev/68/41/ce/ce/6841cece-41f1-4edf-ab9a-59459a127c77 ...
+I, [2018-03-19T15:25:55.074254 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/object_metadata.n3 -- saved
+I, [2018-03-19T15:25:55.124696 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/856444b6-8dd5-4dfa-857d-435e354a2ead/file_set_metadata.n3 -- fetching from http://localhost:8080/fcrepo/rest/dev/85/64/44/b6/856444b6-8dd5-4dfa-857d-435e354a2ead ...
+I, [2018-03-19T15:25:55.163497 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/856444b6-8dd5-4dfa-857d-435e354a2ead/file_set_metadata.n3 -- saved
+I, [2018-03-19T15:25:55.173367 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/856444b6-8dd5-4dfa-857d-435e354a2ead/original_file_metadata.n3 -- fetching from http://localhost:8080/fcrepo/rest/dev/85/64/44/b6/856444b6-8dd5-4dfa-857d-435e354a2ead/files/e1bc671b-b3ce-4f9f-9596-df3cad1d84bb/fcr:metadata ...
+I, [2018-03-19T15:25:55.177168 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/856444b6-8dd5-4dfa-857d-435e354a2ead/original_file_metadata.n3 -- saved
+I, [2018-03-19T15:25:55.192042 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/856444b6-8dd5-4dfa-857d-435e354a2ead/original_file_metadata.n3 -- fetching from http://localhost:8080/fcrepo/rest/dev/85/64/44/b6/856444b6-8dd5-4dfa-857d-435e354a2ead/files/04bb7928-cc5d-4338-8062-3209274b29da/fcr:metadata ...
+I, [2018-03-19T15:25:55.196054 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/856444b6-8dd5-4dfa-857d-435e354a2ead/original_file_metadata.n3 -- saved
+I, [2018-03-19T15:25:55.224521 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/files/856444b6-8dd5-4dfa-857d-435e354a2ead/era-logo.png -- fetching from http://localhost:8080/fcrepo/rest/dev/85/64/44/b6/856444b6-8dd5-4dfa-857d-435e354a2ead/files/04bb7928-cc5d-4338-8062-3209274b29da ...
+I, [2018-03-19T15:25:55.226876 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/files/856444b6-8dd5-4dfa-857d-435e354a2ead/era-logo.png -- saved
+I, [2018-03-19T15:25:55.226973 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/logs/files_logs/856444b6-8dd5-4dfa-857d-435e354a2ead/content_fixity_report.n3 -- fetching from http://localhost:8080/fcrepo/rest/dev/85/64/44/b6/856444b6-8dd5-4dfa-857d-435e354a2ead/files/04bb7928-cc5d-4338-8062-3209274b29da/fcr:fixity ...
+I, [2018-03-19T15:25:55.229338 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/logs/files_logs/856444b6-8dd5-4dfa-857d-435e354a2ead/content_fixity_report.n3 -- saved
+I, [2018-03-19T15:25:55.229559 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/837977d6-de61-49ea-a912-a65af5c9005e/file_set_metadata.n3 -- fetching from http://localhost:8080/fcrepo/rest/dev/83/79/77/d6/837977d6-de61-49ea-a912-a65af5c9005e ...
+I, [2018-03-19T15:25:55.267283 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/837977d6-de61-49ea-a912-a65af5c9005e/file_set_metadata.n3 -- saved
+I, [2018-03-19T15:25:55.278070 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/837977d6-de61-49ea-a912-a65af5c9005e/original_file_metadata.n3 -- fetching from http://localhost:8080/fcrepo/rest/dev/83/79/77/d6/837977d6-de61-49ea-a912-a65af5c9005e/files/956ee84b-ef1a-4e1e-955e-0707e34df4b8/fcr:metadata ...
+I, [2018-03-19T15:25:55.282213 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/837977d6-de61-49ea-a912-a65af5c9005e/original_file_metadata.n3 -- saved
+I, [2018-03-19T15:25:55.311343 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/files/837977d6-de61-49ea-a912-a65af5c9005e/image-sample.jpeg -- fetching from http://localhost:8080/fcrepo/rest/dev/83/79/77/d6/837977d6-de61-49ea-a912-a65af5c9005e/files/956ee84b-ef1a-4e1e-955e-0707e34df4b8 ...
+I, [2018-03-19T15:25:55.313634 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/files/837977d6-de61-49ea-a912-a65af5c9005e/image-sample.jpeg -- saved
+I, [2018-03-19T15:25:55.313742 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/logs/files_logs/837977d6-de61-49ea-a912-a65af5c9005e/content_fixity_report.n3 -- fetching from http://localhost:8080/fcrepo/rest/dev/83/79/77/d6/837977d6-de61-49ea-a912-a65af5c9005e/files/956ee84b-ef1a-4e1e-955e-0707e34df4b8/fcr:fixity ...
+I, [2018-03-19T15:25:55.316106 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/logs/files_logs/837977d6-de61-49ea-a912-a65af5c9005e/content_fixity_report.n3 -- saved
+I, [2018-03-19T15:25:55.316328 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/01bb1b09-974d-478b-8826-2c606a447606/file_set_metadata.n3 -- fetching from http://localhost:8080/fcrepo/rest/dev/01/bb/1b/09/01bb1b09-974d-478b-8826-2c606a447606 ...
+I, [2018-03-19T15:25:55.354159 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/01bb1b09-974d-478b-8826-2c606a447606/file_set_metadata.n3 -- saved
+I, [2018-03-19T15:25:55.364942 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/01bb1b09-974d-478b-8826-2c606a447606/original_file_metadata.n3 -- fetching from http://localhost:8080/fcrepo/rest/dev/01/bb/1b/09/01bb1b09-974d-478b-8826-2c606a447606/files/8b26afd3-0f72-4241-87d4-830f0bbdf58c/fcr:metadata ...
+I, [2018-03-19T15:25:55.369202 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/01bb1b09-974d-478b-8826-2c606a447606/original_file_metadata.n3 -- saved
+I, [2018-03-19T15:25:55.398452 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/files/01bb1b09-974d-478b-8826-2c606a447606/theses.jpg -- fetching from http://localhost:8080/fcrepo/rest/dev/01/bb/1b/09/01bb1b09-974d-478b-8826-2c606a447606/files/8b26afd3-0f72-4241-87d4-830f0bbdf58c ...
+I, [2018-03-19T15:25:55.400813 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/files/01bb1b09-974d-478b-8826-2c606a447606/theses.jpg -- saved
+I, [2018-03-19T15:25:55.400923 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/logs/files_logs/01bb1b09-974d-478b-8826-2c606a447606/content_fixity_report.n3 -- fetching from http://localhost:8080/fcrepo/rest/dev/01/bb/1b/09/01bb1b09-974d-478b-8826-2c606a447606/files/8b26afd3-0f72-4241-87d4-830f0bbdf58c/fcr:fixity ...
+I, [2018-03-19T15:25:55.403282 #32469] INFO -- : 6841cece-41f1-4edf-ab9a-59459a127c77: /tmp/aip/6841cece-41f1-4edf-ab9a-59459a127c77/data/logs/files_logs/01bb1b09-974d-478b-8826-2c606a447606/content_fixity_report.n3 -- saved
diff --git a/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/logs/files_logs/01bb1b09-974d-478b-8826-2c606a447606/content_fixity_report.n3 b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/logs/files_logs/01bb1b09-974d-478b-8826-2c606a447606/content_fixity_report.n3
new file mode 100644
index 0000000..797c205
--- /dev/null
+++ b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/logs/files_logs/01bb1b09-974d-478b-8826-2c606a447606/content_fixity_report.n3
@@ -0,0 +1,42 @@
+@prefix premis: .
+@prefix rdfs: .
+@prefix ns004: .
+@prefix ns003: .
+@prefix ns002: .
+@prefix xsi: .
+@prefix ns001: .
+@prefix ns008: .
+@prefix ns007: .
+@prefix ns006: .
+@prefix xmlns: .
+@prefix ns005: .
+@prefix xml: .
+@prefix ns009: .
+@prefix fedoraconfig: .
+@prefix foaf: .
+@prefix test: .
+@prefix ns011: .
+@prefix ns010: .
+@prefix ns015: .
+@prefix ns014: .
+@prefix ns013: .
+@prefix ns012: .
+@prefix ns019: .
+@prefix ns018: .
+@prefix ns017: .
+@prefix ns016: .
+@prefix fedora: .
+@prefix rdf: .
+@prefix ebucore: .
+@prefix ldp: .
+@prefix xs: .
+@prefix dc: .
+
+
+ premis:hasFixity .
+
+
+ a premis:EventOutcomeDetail , premis:Fixity ;
+ premis:hasEventOutcome "SUCCESS"^^ ;
+ premis:hasMessageDigest ;
+ premis:hasSize "53678"^^ .
diff --git a/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/logs/files_logs/837977d6-de61-49ea-a912-a65af5c9005e/content_fixity_report.n3 b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/logs/files_logs/837977d6-de61-49ea-a912-a65af5c9005e/content_fixity_report.n3
new file mode 100644
index 0000000..d08feab
--- /dev/null
+++ b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/logs/files_logs/837977d6-de61-49ea-a912-a65af5c9005e/content_fixity_report.n3
@@ -0,0 +1,42 @@
+@prefix premis: .
+@prefix rdfs: .
+@prefix ns004: .
+@prefix ns003: .
+@prefix ns002: .
+@prefix xsi: .
+@prefix ns001: .
+@prefix ns008: .
+@prefix ns007: .
+@prefix ns006: .
+@prefix xmlns: .
+@prefix ns005: .
+@prefix xml: .
+@prefix ns009: .
+@prefix fedoraconfig: .
+@prefix foaf: .
+@prefix test: .
+@prefix ns011: .
+@prefix ns010: .
+@prefix ns015: .
+@prefix ns014: .
+@prefix ns013: .
+@prefix ns012: .
+@prefix ns019: .
+@prefix ns018: .
+@prefix ns017: .
+@prefix ns016: .
+@prefix fedora: .
+@prefix rdf: .
+@prefix ebucore: .
+@prefix ldp: .
+@prefix xs: .
+@prefix dc: .
+
+
+ premis:hasFixity .
+
+
+ a premis:EventOutcomeDetail , premis:Fixity ;
+ premis:hasEventOutcome "SUCCESS"^^ ;
+ premis:hasMessageDigest ;
+ premis:hasSize "12401"^^ .
diff --git a/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/logs/files_logs/856444b6-8dd5-4dfa-857d-435e354a2ead/content_fixity_report.n3 b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/logs/files_logs/856444b6-8dd5-4dfa-857d-435e354a2ead/content_fixity_report.n3
new file mode 100644
index 0000000..e14e35f
--- /dev/null
+++ b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/logs/files_logs/856444b6-8dd5-4dfa-857d-435e354a2ead/content_fixity_report.n3
@@ -0,0 +1,42 @@
+@prefix premis: .
+@prefix rdfs: .
+@prefix ns004: .
+@prefix ns003: .
+@prefix ns002: .
+@prefix xsi: .
+@prefix ns001: .
+@prefix ns008: .
+@prefix ns007: .
+@prefix ns006: .
+@prefix xmlns: .
+@prefix ns005: .
+@prefix xml: .
+@prefix ns009: .
+@prefix fedoraconfig: .
+@prefix foaf: .
+@prefix test: .
+@prefix ns011: .
+@prefix ns010: .
+@prefix ns015: .
+@prefix ns014: .
+@prefix ns013: .
+@prefix ns012: .
+@prefix ns019: .
+@prefix ns018: .
+@prefix ns017: .
+@prefix ns016: .
+@prefix fedora: .
+@prefix rdf: .
+@prefix ebucore: .
+@prefix ldp: .
+@prefix xs: .
+@prefix dc: .
+
+
+ a premis:EventOutcomeDetail , premis:Fixity ;
+ premis:hasEventOutcome "SUCCESS"^^ ;
+ premis:hasMessageDigest ;
+ premis:hasSize "5612"^^ .
+
+
+ premis:hasFixity .
diff --git a/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/files/01bb1b09-974d-478b-8826-2c606a447606/theses.jpg b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/files/01bb1b09-974d-478b-8826-2c606a447606/theses.jpg
new file mode 100644
index 0000000..a676cf6
Binary files /dev/null and b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/files/01bb1b09-974d-478b-8826-2c606a447606/theses.jpg differ
diff --git a/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/files/837977d6-de61-49ea-a912-a65af5c9005e/image-sample.jpeg b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/files/837977d6-de61-49ea-a912-a65af5c9005e/image-sample.jpeg
new file mode 100644
index 0000000..3853a5e
Binary files /dev/null and b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/files/837977d6-de61-49ea-a912-a65af5c9005e/image-sample.jpeg differ
diff --git a/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/files/856444b6-8dd5-4dfa-857d-435e354a2ead/era-logo.png b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/files/856444b6-8dd5-4dfa-857d-435e354a2ead/era-logo.png
new file mode 100644
index 0000000..df281fc
Binary files /dev/null and b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/files/856444b6-8dd5-4dfa-857d-435e354a2ead/era-logo.png differ
diff --git a/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/01bb1b09-974d-478b-8826-2c606a447606/file_set_metadata.n3 b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/01bb1b09-974d-478b-8826-2c606a447606/file_set_metadata.n3
new file mode 100644
index 0000000..a753dc3
--- /dev/null
+++ b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/01bb1b09-974d-478b-8826-2c606a447606/file_set_metadata.n3
@@ -0,0 +1,35 @@
+@prefix ebucore: .
+@prefix fedora: .
+@prefix ldp: .
+@prefix ns001: .
+@prefix ns002: .
+@prefix ns003: .
+@prefix ns005: .
+@prefix ns007: .
+@prefix ns010: .
+@prefix rdf: .
+@prefix xs: .
+
+ a ldp:Container,
+ ns005:Object,
+ fedora:Container,
+ ldp:RDFSource,
+ ns007:FileSet,
+ fedora:Resource;
+ ns003:title "theses.jpg";
+ fedora:created "2018-03-09T18:53:30.313Z"^^;
+ fedora:createdBy "bypassAdmin";
+ fedora:hasParent ;
+ fedora:lastModified "2018-03-09T18:53:30.663Z"^^;
+ fedora:lastModifiedBy "bypassAdmin";
+ fedora:writable true;
+ ns005:hasFile ;
+ ns005:memberOf ;
+ ns003:accessRights "http://terms.library.ualberta.ca/public";
+ ns002:owner "admin@ualberta.ca";
+ ns010:recordCreatedInJupiter "2018-03-09T18:53:30.296Z";
+ ns010:sitemapLink "";
+ ebucore:dateIngested "2018-03-09T18:53:30.296Z";
+ ldp:contains ,
+ ;
+ ns001:hasModel "IRFileSet" .
diff --git a/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/01bb1b09-974d-478b-8826-2c606a447606/original_file_metadata.n3 b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/01bb1b09-974d-478b-8826-2c606a447606/original_file_metadata.n3
new file mode 100644
index 0000000..55969db
--- /dev/null
+++ b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/01bb1b09-974d-478b-8826-2c606a447606/original_file_metadata.n3
@@ -0,0 +1,61 @@
+@prefix premis: .
+@prefix rdfs: .
+@prefix ns004: .
+@prefix ns003: .
+@prefix ns002: .
+@prefix xsi: .
+@prefix ns001: .
+@prefix ns008: .
+@prefix ns007: .
+@prefix ns006: .
+@prefix xmlns: .
+@prefix ns005: .
+@prefix xml: .
+@prefix ns009: .
+@prefix fedoraconfig: .
+@prefix foaf: .
+@prefix test: .
+@prefix ns011: .
+@prefix ns010: .
+@prefix ns015: .
+@prefix ns014: .
+@prefix ns013: .
+@prefix ns012: .
+@prefix ns019: .
+@prefix ns018: .
+@prefix ns017: .
+@prefix ns016: .
+@prefix fedora: .
+@prefix rdf: .
+@prefix ebucore: .
+@prefix ldp: .
+@prefix xs: .
+@prefix dc: .
+
+
+ a ldp:NonRDFSource , ns011:OriginalFile , fedora:Resource , ns005:File , fedora:Binary ;
+ fedora:created "2018-03-09T18:53:30.447Z"^^ ;
+ fedora:createdBy "bypassAdmin"^^ ;
+ fedora:hasFixityService ;
+ fedora:hasParent ;
+ fedora:lastModified "2018-03-09T18:53:32.99Z"^^ ;
+ fedora:lastModifiedBy "bypassAdmin"^^ ;
+ fedora:writable "true"^^ ;
+ ns017:valid "true"^^ ;
+ ns017:wellFormed "true"^^ ;
+ ns019:compressionScheme "JPEG"^^ ;
+ ns018:byteOrder "big endian"^^ ;
+ ebucore:fileSize "53678"^^ ;
+ ebucore:filename "theses.jpg"^^ ;
+ ebucore:hasMimeType "image/jpeg"^^ ;
+ ebucore:height "335"^^ ;
+ ebucore:width "504"^^ ;
+ ns014:describedby ;
+ premis:hasCreatingApplicationVersion
+ "1.2.0"^^ ;
+ premis:hasFormatName "JPEG File Interchange Format"^^ ;
+ premis:hasMessageDigest ;
+ premis:hasSize "53678"^^ ;
+ ns016:hashValue "59ced23d3250b0cf54a58dd21bad4512"^^ ;
+ ns015:colorSpace "YCbCr"^^ ;
+ ns015:exifVersion "10.00"^^ .
diff --git a/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/837977d6-de61-49ea-a912-a65af5c9005e/file_set_metadata.n3 b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/837977d6-de61-49ea-a912-a65af5c9005e/file_set_metadata.n3
new file mode 100644
index 0000000..89f882b
--- /dev/null
+++ b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/837977d6-de61-49ea-a912-a65af5c9005e/file_set_metadata.n3
@@ -0,0 +1,35 @@
+@prefix ebucore: .
+@prefix fedora: .
+@prefix ldp: .
+@prefix ns001: .
+@prefix ns002: .
+@prefix ns003: .
+@prefix ns005: .
+@prefix ns007: .
+@prefix ns010: .
+@prefix rdf: .
+@prefix xs: .
+
+ a ldp:Container,
+ ns005:Object,
+ fedora:Container,
+ fedora:Resource,
+ ns007:FileSet,
+ ldp:RDFSource;
+ ns003:title "image-sample.jpeg";
+ fedora:created "2018-03-09T18:53:33.018Z"^^;
+ fedora:createdBy "bypassAdmin";
+ fedora:hasParent ;
+ fedora:lastModified "2018-03-09T18:53:33.375Z"^^;
+ fedora:lastModifiedBy "bypassAdmin";
+ fedora:writable true;
+ ns005:hasFile ;
+ ns005:memberOf ;
+ ns003:accessRights "http://terms.library.ualberta.ca/public";
+ ns002:owner "admin@ualberta.ca";
+ ns010:recordCreatedInJupiter "2018-03-09T18:53:32.996Z";
+ ns010:sitemapLink "";
+ ebucore:dateIngested "2018-03-09T18:53:32.996Z";
+ ldp:contains ,
+ ;
+ ns001:hasModel "IRFileSet" .
diff --git a/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/837977d6-de61-49ea-a912-a65af5c9005e/original_file_metadata.n3 b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/837977d6-de61-49ea-a912-a65af5c9005e/original_file_metadata.n3
new file mode 100644
index 0000000..19b6b7e
--- /dev/null
+++ b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/837977d6-de61-49ea-a912-a65af5c9005e/original_file_metadata.n3
@@ -0,0 +1,61 @@
+@prefix premis: .
+@prefix rdfs: .
+@prefix ns004: .
+@prefix ns003: .
+@prefix ns002: .
+@prefix xsi: .
+@prefix ns001: .
+@prefix ns008: .
+@prefix ns007: .
+@prefix ns006: .
+@prefix xmlns: .
+@prefix ns005: .
+@prefix xml: .
+@prefix ns009: .
+@prefix fedoraconfig: .
+@prefix foaf: .
+@prefix test: .
+@prefix ns011: .
+@prefix ns010: .
+@prefix ns015: .
+@prefix ns014: .
+@prefix ns013: .
+@prefix ns012: .
+@prefix ns019: .
+@prefix ns018: .
+@prefix ns017: .
+@prefix ns016: .
+@prefix fedora: .
+@prefix rdf: .
+@prefix ebucore: .
+@prefix ldp: .
+@prefix xs: .
+@prefix dc: .
+
+
+ a fedora:Binary , fedora:Resource , ldp:NonRDFSource , ns011:OriginalFile , ns005:File ;
+ fedora:created "2018-03-09T18:53:33.16Z"^^ ;
+ fedora:createdBy "bypassAdmin"^^ ;
+ fedora:hasFixityService ;
+ fedora:hasParent ;
+ fedora:lastModified "2018-03-09T18:53:35.73Z"^^ ;
+ fedora:lastModifiedBy "bypassAdmin"^^ ;
+ fedora:writable "true"^^ ;
+ ns017:valid "true"^^ ;
+ ns017:wellFormed "true"^^ ;
+ ns019:compressionScheme "JPEG"^^ ;
+ ns018:byteOrder "big endian"^^ ;
+ ebucore:fileSize "12401"^^ ;
+ ebucore:filename "image-sample.jpeg"^^ ;
+ ebucore:hasMimeType "image/jpeg"^^ ;
+ ebucore:height "183"^^ ;
+ ebucore:width "276"^^ ;
+ ns014:describedby ;
+ premis:hasCreatingApplicationVersion
+ "1.2.0"^^ ;
+ premis:hasFormatName "JPEG File Interchange Format"^^ ;
+ premis:hasMessageDigest ;
+ premis:hasSize "12401"^^ ;
+ ns016:hashValue "71179c73ffd133cf0f25e3f7b3572ef7"^^ ;
+ ns015:colorSpace "YCbCr"^^ ;
+ ns015:exifVersion "10.00"^^ .
diff --git a/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/856444b6-8dd5-4dfa-857d-435e354a2ead/file_set_metadata.n3 b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/856444b6-8dd5-4dfa-857d-435e354a2ead/file_set_metadata.n3
new file mode 100644
index 0000000..51ed63d
--- /dev/null
+++ b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/856444b6-8dd5-4dfa-857d-435e354a2ead/file_set_metadata.n3
@@ -0,0 +1,36 @@
+@prefix ebucore: .
+@prefix fedora: .
+@prefix ldp: .
+@prefix ns001: .
+@prefix ns002: .
+@prefix ns003: .
+@prefix ns005: .
+@prefix ns007: .
+@prefix ns010: .
+@prefix rdf: .
+@prefix xs: .
+
+ a ldp:Container,
+ ns005:Object,
+ fedora:Container,
+ fedora:Resource,
+ ns007:FileSet,
+ ldp:RDFSource;
+ ns003:title "era-logo.png";
+ fedora:created "2018-03-09T18:53:35.759Z"^^;
+ fedora:createdBy "bypassAdmin";
+ fedora:hasParent ;
+ fedora:lastModified "2018-03-09T18:53:39.162Z"^^;
+ fedora:lastModifiedBy "bypassAdmin";
+ fedora:writable true;
+ ns005:hasFile ,
+ ;
+ ns005:memberOf ;
+ ns003:accessRights "http://terms.library.ualberta.ca/public";
+ ns002:owner "admin@ualberta.ca";
+ ns010:recordCreatedInJupiter "2018-03-09T18:53:35.736Z";
+ ns010:sitemapLink "";
+ ebucore:dateIngested "2018-03-09T18:53:35.736Z";
+ ldp:contains ,
+ ;
+ ns001:hasModel "IRFileSet" .
diff --git a/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/856444b6-8dd5-4dfa-857d-435e354a2ead/original_file_metadata.n3 b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/856444b6-8dd5-4dfa-857d-435e354a2ead/original_file_metadata.n3
new file mode 100644
index 0000000..fee5984
--- /dev/null
+++ b/spec/fixtures/aip_download/6841cece-41f1-4edf-ab9a-59459a127c77/data/objects/metadata/files_metadata/856444b6-8dd5-4dfa-857d-435e354a2ead/original_file_metadata.n3
@@ -0,0 +1,58 @@
+@prefix premis: .
+@prefix rdfs: .
+@prefix ns004: .
+@prefix ns003: .
+@prefix ns002: .
+@prefix xsi: .
+@prefix ns001: .
+@prefix ns008: .
+@prefix ns007: .
+@prefix ns006: .
+@prefix xmlns: .
+@prefix ns005: .
+@prefix xml: .
+@prefix ns009: .
+@prefix fedoraconfig: .
+@prefix foaf: .
+@prefix test: .
+@prefix ns011: .
+@prefix ns010: .
+@prefix ns015: .
+@prefix ns014: .
+@prefix ns013: .
+@prefix ns012: .
+@prefix ns019: .
+@prefix ns018: .
+@prefix ns017: .
+@prefix ns016: .
+@prefix fedora: .
+@prefix rdf: .
+@prefix ebucore: .
+@prefix ldp: .
+@prefix xs: .
+@prefix dc: .
+
+
+ a ns011:OriginalFile , fedora:Resource , fedora:Binary , ldp:NonRDFSource , ns005:File ;
+ fedora:created "2018-03-09T18:53:35.896Z"^^ ;
+ fedora:createdBy "bypassAdmin"^^ ;
+ fedora:hasFixityService ;
+ fedora:hasParent ;
+ fedora:lastModified "2018-03-09T18:53:38.335Z"^^ ;
+ fedora:lastModifiedBy "bypassAdmin"^^ ;
+ fedora:writable "true"^^ ;
+ ns019:compressionScheme "Deflate/Inflate"^^ , "Deflate"^^ ;
+ ebucore:fileSize "5612"^^ ;
+ ebucore:filename "era-logo.png"^^ ;
+ ebucore:hasMimeType "image/png"^^ ;
+ ebucore:height "114"^^ ;
+ ebucore:width "208"^^