sul-dlss/argo

View on GitHub
app/jobs/descriptive_metadata_import_job.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
91%
# frozen_string_literal: true

class DescriptiveMetadataImportJob < GenericJob
  include Dry::Monads[:result]
  queue_as :default

  ##
  # A job that allows a user to make descriptive updates from a CSV file
  # @param [Integer] bulk_action_id GlobalID for a BulkAction object
  # @param [Hash] params additional parameters that an Argo job may need
  # @option params [String] :csv_file file
  # @option params [String] :csv_filename the name of the file
  def perform(bulk_action_id, params)
    super
    csv = CSV.parse(params[:csv_file], headers: true)
    with_csv_items(csv, name: 'Import descriptive metadata',
                        filename: params[:csv_filename]) do |cocina_object, csv_row, success, failure|
      next failure.call('Not authorized') unless ability.can?(:update, cocina_object)

      DescriptionImport.import(csv_row:)
                       .bind { |description| validate_input(cocina_object, description) }
                       .bind { |description| validate_changed(cocina_object, description) }
                       .bind { |description| open_version(cocina_object, description) }
                       .bind { |description, new_cocina_object| save(new_cocina_object, description) }
                       .bind { |new_cocina_object| close_version(new_cocina_object) }
                       .either(
                         ->(_updated) { success.call('Successfully updated') },
                         ->(messages) { failure.call(messages.to_sentence) }
                       )
    end
  end

  private

  # this validates input data from spreadsheet before any updates are applied to provide error messages to the user
  def validate_input(cocina_object, description)
    result = CocinaValidator.validate(cocina_object, description:)
    return Success(description) if result.success?

    Failure(["validation failed for #{cocina_object.externalIdentifier}: #{result.failure}"])
  end

  def validate_changed(cocina_object, description)
    return Failure(['Description unchanged']) if cocina_object.description == description

    Success(description)
  end

  def open_version(cocina_object, description)
    cocina_object = open_new_version_if_needed(cocina_object, 'Descriptive metadata upload')

    Success([description, cocina_object])
  rescue RuntimeError => e
    Failure([e.message])
  end

  def save(cocina_object, description)
    updated_object = cocina_object.new(description:)
    Repository.store(updated_object)
    Success(updated_object)
  rescue RuntimeError => e
    Failure(["save failed for #{cocina_object.externalIdentifier}: #{e.message}"])
  end

  def close_version(cocina_object)
    VersionService.close(druid: cocina_object.externalIdentifier)
    Success()
  rescue RuntimeError => e
    Failure([e.message])
  end
end