sul-dlss/pre-assembly

View on GitHub
app/lib/pre_assembly/from_file_manifest/file_set_builder.rb

Summary

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

module PreAssembly
  module FromFileManifest
    # Creates a hash representing the Cocina::FileSets from a file manifest
    class FileSetBuilder
      # @param [Cocina::Models::DRO] cocina_dro
      def self.build(resource:, cocina_dro:, external_identifier:, staging_location:)
        new(
          resource:,
          cocina_dro:,
          external_identifier:,
          staging_location:
        ).build
      end

      def initialize(resource:, cocina_dro:, external_identifier:, staging_location:)
        @resource = resource
        @cocina_dro = cocina_dro
        @external_identifier = external_identifier
        @staging_location = staging_location
      end

      attr_reader :resource, :cocina_dro, :external_identifier, :staging_location

      def build
        {
          label: resource[:label] || '',
          type: resource_type(resource[:resource_type]),
          externalIdentifier: external_identifier,
          version: cocina_dro.version,
          structural:
        }
      end

      private

      def resource_type(val)
        val = 'three_dimensional' if val == '3d'
        return Cocina::Models::FileSetType.public_send(val) if val && Cocina::Models::FileSetType.respond_to?(val)

        raise "Invalid resource type: '#{val}'"
      end

      def structural
        { contains: build_files }
      end

      def build_files
        resource[:files].map { |file_attributes| file_builder(file_attributes:) }
      end

      def file_builder(file_attributes:)
        attrs = file_attributes
                .merge(version: cocina_dro.version, access: file_access(file_attributes))
                .merge(existing_cocina_file_attributes(filename: file_attributes[:filename], mimetype_present: file_attributes[:hasMimeType].present?))
        Cocina::Models::File.new(attrs)
      end

      def existing_cocina_file_attributes(filename:, mimetype_present:)
        return {} if file_exists?(filename)
        return {} unless (existing_cocina_file = existing_cocina_files[filename])

        fields = :externalIdentifier, :hasMessageDigests, :size, :presentation, :sdrGeneratedText, :correctedForAccessibility
        fields << :hasMimeType unless mimetype_present

        existing_cocina_file.to_h.slice(*fields)
      end

      def file_exists?(filename)
        File.exist?(File.join(staging_location, cocina_dro.externalIdentifier.delete_prefix('druid:'), filename))
      end

      def file_access(file_attributes)
        return file_attributes[:access] if file_attributes[:access].present?

        file_access = cocina_dro.access.to_h.slice(:view, :download, :location, :controlledDigitalLending)
        file_access[:view] = 'dark' if file_access[:view] == 'citation-only'
        file_access
      end

      def existing_cocina_files
        @existing_cocina_files = cocina_dro.structural.contains.flat_map do |file_set|
          file_set.structural.contains.map { |file| [file.filename, file] }
        end.to_h
      end
    end
  end
end