Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

i162 - import valkyrie works with filesets #936

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
71cec53
Revert "WIP - try to import filesets with valkyrie resources"
ShanaLMoore Mar 11, 2024
ad06786
WIP
ShanaLMoore Mar 11, 2024
6c4490b
WIP - try to import filesets with valkyrie resources
ShanaLMoore Mar 11, 2024
6f0c049
🚧 WIP: get filesets to import via bulkrax x valkyrie
ShanaLMoore Mar 12, 2024
d2cde2b
Merge branch 'i161-import-collection-resources' into i162-import-valk…
ShanaLMoore Mar 12, 2024
d4d7d29
:tada: WIP: filesets to imports via bulkrax x valkyrie
ShanaLMoore Mar 12, 2024
6d48b29
💄 rubocop fixes
ShanaLMoore Mar 12, 2024
b9bb435
uncomment #get_s3_files call and add collections to configuration
ShanaLMoore Mar 13, 2024
178349e
Update object_factory.rb
ShanaLMoore Mar 13, 2024
5ca0411
♻️ Move method and remove single instance definition
jeremyf Mar 13, 2024
844250a
Merge branch 'move-method' into i162-import-valkyrie-works-and-filesets
ShanaLMoore Mar 13, 2024
1375a58
Revert changes due to refactor coming in from main
ShanaLMoore Mar 13, 2024
ee461a6
Merge branch 'main' into i162-import-valkyrie-works-and-filesets
ShanaLMoore Mar 13, 2024
bf94442
Merge branch 'hyrax-4-valkyrie-support' into i162-import-valkyrie-wor…
ShanaLMoore Mar 14, 2024
3ff48e9
Merge branch 'i161-import-collection-resources' into i162-import-valk…
ShanaLMoore Mar 14, 2024
c0e9246
Merge branch 'hyrax-4-valkyrie-support' into i162-import-valkyrie-wor…
ShanaLMoore Mar 14, 2024
341e905
address errors post big refactor
ShanaLMoore Mar 14, 2024
61ea025
Merge branch 'i161-import-collection-resources' into i162-import-valk…
ShanaLMoore Mar 14, 2024
38770ca
Merge branch 'hyrax-4-valkyrie-support' into i162-import-valkyrie-wor…
jeremyf Mar 14, 2024
8ea0388
Refactoring for consistent method signatures
jeremyf Mar 14, 2024
99118a3
:bug: remove passing user to work_resource add_file_sets and save mer…
ShanaLMoore Mar 14, 2024
bd54be5
🎁 Adding a new transaction step to handle different association
jeremyf Mar 14, 2024
99c712b
♻️ Extract update_index method to object factory
jeremyf Mar 15, 2024
b31b5d2
♻️ Extract object factory method
jeremyf Mar 15, 2024
ce70bd9
♻️ Extract add_resource_to_collection method
jeremyf Mar 15, 2024
74a6b40
♻️ XIT out the mockery and stubbery of a spec
jeremyf Mar 15, 2024
ab86f4c
♻️ Extract method publish and add_child_to_parent_work
jeremyf Mar 15, 2024
620c991
♻️ Rename method as it's not conditional
jeremyf Mar 15, 2024
267d223
Remove add to collection step
jeremyf Mar 15, 2024
3264490
🐛 Fix publish parameter mismatch
jeremyf Mar 15, 2024
c7f99d1
Removing custom transaction container. We weren't using it
jeremyf Mar 15, 2024
4c9bec1
Favor keyword args instead of hashes
jeremyf Mar 15, 2024
1f363e1
💄fixing typo
ShanaLMoore Mar 15, 2024
ea0c95c
🎁 Add update_collection to valkyrie object factory
ShanaLMoore Mar 15, 2024
2060f69
💄 endless and ever appeasing of the coppers
jeremyf Mar 15, 2024
92ba151
Merge branch 'i161-import-collection-resources' into i162-import-valk…
jeremyf Mar 15, 2024
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
32 changes: 32 additions & 0 deletions app/factories/bulkrax/object_factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,26 @@ class ObjectFactory # rubocop:disable Metrics/ClassLength
##
# @!group Class Method Interface

##
# @note This does not save either object. We need to do that in another
# loop. Why? Because we might be adding many items to the parent.
def self.add_child_to_parent_work(parent:, child:)
return true if parent.ordered_members.to_a.include?(child_record)

parent.ordered_members << child
end

def self.add_resource_to_collection(collection:, resource:, user:)
collection.try(:reindex_extent=, Hyrax::Adapters::NestingIndexAdapter::LIMITED_REINDEX) if
defined?(Hyrax::Adapters::NestingIndexAdapter)
resource.member_of_collections << collection
save!(resource: resource, user: user)
end

def self.update_index_for_file_sets_of(resource:)
resource.file_sets.each(&:update_index) if resource.respond_to?(:file_sets)
end

##
# @see Bulkrax::ObjectFactoryInterface
def self.export_properties
Expand All @@ -28,6 +48,10 @@ def self.find(id)
raise ObjectFactoryInterface::ObjectNotFoundError, e.message
end

def self.publish(**)
return true
end

##
# @param value [String]
# @param klass [Class, #where]
Expand Down Expand Up @@ -93,9 +117,17 @@ def self.solr_name(field_name)
end
end

def self.ordered_file_sets_for(object)
object&.ordered_members.to_a.select(&:file_set?)
end

def self.save!(resource:, **)
resource.save!
end

def self.update_index(resources: [])
Array(resources).each(&:update_index)
end
# @!endgroup Class Method Interface
##

Expand Down
52 changes: 40 additions & 12 deletions app/factories/bulkrax/object_factory_interface.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,36 @@ class RecordInvalid < ActiveRecord::RecordInvalid
end

class_methods do
##
# @note This does not save either object. We need to do that in another
# loop. Why? Because we might be adding many items to the parent.
def add_child_to_parent_work(parent:, child:)
raise NotImplementedError, "#{self}.#{__method__}"
end

def add_resource_to_collection(collection:, resource:, user:)
raise NotImplementedError, "#{self}.#{__method__}"
end

##
# @yield when Rails application is running in test environment.
def clean!
return true unless Rails.env.test?
yield
end

##
# @param resource [Object] something that *might* have file_sets members.
def update_index_for_file_sets_of(resource:)
raise NotImplementedError, "#{self}.#{__method__}"
end

##
# @return [Array<String>]
def export_properties
raise NotImplementedError, "#{self}.#{__method__}"
end

##
# @see ActiveFedora::Base.find
def find(id)
Expand All @@ -36,32 +66,30 @@ def find_or_nil(id)
nil
end

##
# @return [Array<String>]
def export_properties
def publish(event:, **kwargs)
raise NotImplementedError, "#{self}.#{__method__}"
end

def solr_name(field_name)
def query(q, **kwargs)
raise NotImplementedError, "#{self}.#{__method__}"
end

# @yield when Rails application is running in test environment.
def clean!
return true unless Rails.env.test?
yield
def save!(resource:, user:)
raise NotImplementedError, "#{self}.#{__method__}"
end

def query(q, **kwargs)
# rubocop:disable Metrics/ParameterLists
def search_by_property(value:, klass:, field: nil, search_field: nil, name_field: nil, verify_property: false)
raise NotImplementedError, "#{self}.#{__method__}"
end

def save!(resource:, user:)
def solr_name(field_name)
raise NotImplementedError, "#{self}.#{__method__}"
end

# rubocop:disable Metrics/ParameterLists
def search_by_property(value:, klass:, field: nil, search_field: nil, name_field: nil, verify_property: false)
##
# @param resources [Array<Object>]
def update_index(resources: [])
raise NotImplementedError, "#{self}.#{__method__}"
end
# rubocop:enable Metrics/ParameterLists
Expand Down
135 changes: 95 additions & 40 deletions app/factories/bulkrax/valkyrie_object_factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,43 @@ module Bulkrax
class ValkyrieObjectFactory < ObjectFactory
include ObjectFactoryInterface

##
# When you want a different set of transactions you can change the
# container.
#
# @note Within {Bulkrax::ValkyrieObjectFactory} there are several calls to
# transactions; so you'll need your container to register those
# transactions.
def self.transactions
@transactions || Hyrax::Transactions::Container
end

def transactions
self.class.transactions
end

##
# @!group Class Method Interface

##
# @note This does not save either object. We need to do that in another
# loop. Why? Because we might be adding many items to the parent.
def self.add_child_to_parent_work(parent:, child:)
return true if parent.member_ids.include?(child.id)

parent.member_ids << child.id
end

def self.add_resource_to_collection(collection:, resource:, user:)
resource.member_of_collection_ids << collection.id
save!(resource: resource, user: user)
end

def self.update_index_for_file_sets_of(resource:)
file_sets = Hyrax.query_service.custom_queries.find_child_file_sets(resource: resource)
update_index(resources: file_sets)
end

def self.find(id)
if defined?(Hyrax)
begin
Expand All @@ -28,6 +65,10 @@ def self.solr_name(field_name)
Hyrax.config.index_field_mapper.solr_name(field_name)
end

def self.publish(event:, **kwargs)
Hyrax.publisher.publish(event, **kwargs)
end

def self.query(q, **kwargs)
# Someone could choose ActiveFedora::SolrService. But I think we're
# assuming Valkyrie is specifcally working for Hyrax. Someone could make
Expand All @@ -36,22 +77,28 @@ def self.query(q, **kwargs)
Hyrax::SolrService.query(q, **kwargs)
end

def self.save!(resource:, user:, persister: Hyrax.persister, index_adapter: Hyrax.index_adapter)
def self.save!(resource:, user:)
if resource.respond_to?(:save!)
resource.save!
else
result = persister.save(resource: resource)
result = Hyrax.persister.save(resource: resource)
raise Valkyrie::Persistence::ObjectNotFoundError unless result
index_adapter.save(resource: result)
Hyrax.index_adapter.save(resource: result)
if result.collection?
Hyrax.publisher.publish('collection.metadata.updated', collection: result, user: user)
publish('collection.metadata.updated', collection: result, user: user)
else
Hyrax.publisher.publish('object.metadata.updated', object: result, user: user)
publish('object.metadata.updated', object: result, user: user)
end
resource
end
end

def self.update_index(resources:)
Array(resources).each do |resource|
Hyrax.index_adapter.save(resource: resource)
end
end

##
# @param value [String]
# @param klass [Class, #where]
Expand Down Expand Up @@ -85,6 +132,12 @@ def self.schema_properties(klass)
@schema_properties_map[klass_key]
end

def self.ordered_file_sets_for(object)
return [] if object.blank?

Hyrax.custom_queries.find_child_file_sets(resource: object)
end

def run!
run
return object if object.persisted?
Expand Down Expand Up @@ -118,11 +171,12 @@ def create
end

def create_work(object:, attrs:)
# NOTE: We do not add relationships here; that is part of the create
# relationships job.
perform_transaction_for(object: object, attrs: attrs) do
transactions["work_resource.create_with_bulk_behavior"]
transactions["change_set.create_work"]
.with_step_args(
"work_resource.add_to_parent" => { parent_id: attrs[related_parents_parsed_mapping], user: @user },
"work_resource.add_bulkrax_files" => { files: get_s3_files(remote_files: attributes["remote_files"]), user: @user },
'work_resource.add_file_sets' => { uploaded_files: get_files(attrs) },
"change_set.set_user_as_depositor" => { user: @user },
"work_resource.change_depositor" => { user: @user },
'work_resource.save_acl' => { permissions_params: [attrs['visibility'] || 'open'].compact }
Expand All @@ -131,11 +185,12 @@ def create_work(object:, attrs:)
end

def create_collection(object:, attrs:)
# NOTE: We do not add relationships here; that is part of the create
# relationships job.
perform_transaction_for(object: object, attrs: attrs) do
transactions['change_set.create_collection']
.with_step_args(
'change_set.set_user_as_depositor' => { user: @user },
'change_set.add_to_collections' => { collection_ids: Array(attrs[related_parents_parsed_mapping]) },
'collection_resource.apply_collection_type_permissions' => { user: @user }
)
end
Expand All @@ -149,9 +204,10 @@ def update

@object = case @object
when Bulkrax.collection_model_class
# TODO: update_collection(attrs)
update_collection(object: @object, attrs: attrs)
when Bulkrax.file_model_class
# TODO: update_file_set(attrs)
raise "FileSet update not implemented"
when Hyrax::Resource
update_work(object: @object, attrs: attrs)
else
Expand All @@ -161,11 +217,19 @@ def update

def update_work(object:, attrs:)
perform_transaction_for(object: object, attrs: attrs) do
transactions["work_resource.update_with_bulk_behavior"]
transactions["change_set.update_work"]
.with_step_args(
"work_resource.add_bulkrax_files" => { files: get_s3_files(remote_files: attrs["remote_files"]), user: @user },
'work_resource.save_acl' => { permissions_params: [attrs.try('visibility') || 'open'].compact }
)
'work_resource.add_file_sets' => { uploaded_files: get_files(attrs) },
'work_resource.save_acl' => { permissions_params: [attrs.try('visibility') || 'open'].compact }
)
end
end

def update_collection(object:, attrs:)
# NOTE: We do not add relationships here; that is part of the create
# relationships job.
perform_transaction_for(object: object, attrs: attrs) do
transactions['change_set.update_collection']
end
end

Expand Down Expand Up @@ -202,11 +266,18 @@ def perform_transaction_for(object:, attrs:)
end
end

def get_s3_files(remote_files: {})
if remote_files.blank?
Hyrax.logger.info "No remote files listed for #{attributes['source_identifier']}"
return []
def get_files(attrs)
get_local_files(uploaded_files: attrs[:uploaded_files]) + get_s3_files(remote_files: attrs[:remote_files])
end

def get_local_files(uploaded_files: [])
Array.wrap(uploaded_files).map do |file_id|
Hyrax::UploadedFile.find(file_id)
end
end

def get_s3_files(remote_files: {})
return [] if remote_files.blank?

s3_bucket_name = ENV.fetch("STAGING_AREA_S3_BUCKET", "comet-staging-area-#{Rails.env}")
s3_bucket = Rails.application.config.staging_area_s3_connection
Expand All @@ -227,8 +298,9 @@ def permitted_attributes

def apply_depositor_metadata(object, user)
object.depositor = user.email
# TODO: Should we leverage the object factory's save! method?
object = Hyrax.persister.save(resource: object)
Hyrax.publisher.publish("object.metadata.updated", object: object, user: @user)
self.class.publish(event: "object.metadata.updated", object: object, user: @user)
object
end

Expand All @@ -251,10 +323,10 @@ def new_remote_files

def conditionally_destroy_existing_files
return unless @replace_files
case klass
when Bulkrax.collection_model_class, Bulkrax.file_model_class

if [Bulkrax.collection_model_class, Bulkrax.file_model_class].include?(klass)
return
when Valkyrie::Resource
elsif klass < Valkyrie::Resource
destroy_existing_files
else
raise "Unexpected #{klass} for #{self.class}##{__method__}"
Expand Down Expand Up @@ -285,7 +357,7 @@ def delete(user)

Hyrax.persister.delete(resource: obj)
Hyrax.index_adapter.delete(resource: obj)
Hyrax.publisher.publish('object.deleted', object: obj, user: user)
self.class.publish(event: 'object.deleted', object: obj, user: user)
end

private
Expand All @@ -294,23 +366,6 @@ def delete(user)
def fetch_child_file_sets(resource:)
Hyrax.custom_queries.find_child_file_sets(resource: resource)
end

##
# @api public
#
# @return [#[]] a resolver for Hyrax's Transactions; this *should* be a
# thread-safe {Dry::Container}, but callers to this method should strictly
# use +#[]+ for access.
#
# @example
# transactions['change_set.create_work'].call(my_form)
#
# @see Hyrax::Transactions::Container
# @see Hyrax::Transactions::Transaction
# @see https://dry-rb.org/gems/dry-container
def transactions
Hyrax::Transactions::Container
end
end
# rubocop:enable Metrics/ClassLength
end
Loading
Loading