valkyrie 2.1.0 → 3.0.0.pre.beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/.circleci/config.yml +71 -36
 - data/.lando.yml +58 -0
 - data/.rubocop.yml +11 -1
 - data/.tool-versions +1 -1
 - data/CHANGELOG.md +94 -13
 - data/CONTRIBUTING.md +30 -8
 - data/README.md +24 -48
 - data/Rakefile +26 -20
 - data/db/config.yml +3 -10
 - data/lib/generators/valkyrie/resource_generator.rb +3 -3
 - data/lib/valkyrie/change_set.rb +3 -3
 - data/lib/valkyrie/id.rb +12 -19
 - data/lib/valkyrie/indexers/access_controls_indexer.rb +17 -17
 - data/lib/valkyrie/persistence/buffered_persister.rb +2 -2
 - data/lib/valkyrie/persistence/composite_persister.rb +3 -3
 - data/lib/valkyrie/persistence/custom_query_container.rb +8 -16
 - data/lib/valkyrie/persistence/fedora/list_node.rb +43 -43
 - data/lib/valkyrie/persistence/fedora/metadata_adapter.rb +5 -1
 - data/lib/valkyrie/persistence/fedora/ordered_list.rb +90 -90
 - data/lib/valkyrie/persistence/fedora/ordered_reader.rb +5 -5
 - data/lib/valkyrie/persistence/fedora/permissive_schema.rb +1 -1
 - data/lib/valkyrie/persistence/fedora/persister/model_converter.rb +15 -16
 - data/lib/valkyrie/persistence/fedora/persister/orm_converter.rb +14 -19
 - data/lib/valkyrie/persistence/fedora/persister.rb +83 -83
 - data/lib/valkyrie/persistence/fedora/query_service.rb +39 -41
 - data/lib/valkyrie/persistence/memory/persister.rb +51 -35
 - data/lib/valkyrie/persistence/memory/query_service.rb +26 -30
 - data/lib/valkyrie/persistence/postgres/orm_converter.rb +52 -52
 - data/lib/valkyrie/persistence/postgres/persister.rb +4 -1
 - data/lib/valkyrie/persistence/postgres/query_service.rb +34 -34
 - data/lib/valkyrie/persistence/shared/json_value_mapper.rb +1 -1
 - data/lib/valkyrie/persistence/solr/metadata_adapter.rb +15 -3
 - data/lib/valkyrie/persistence/solr/model_converter.rb +323 -340
 - data/lib/valkyrie/persistence/solr/orm_converter.rb +4 -4
 - data/lib/valkyrie/persistence/solr/persister.rb +16 -4
 - data/lib/valkyrie/persistence/solr/queries/find_by_alternate_identifier_query.rb +1 -1
 - data/lib/valkyrie/persistence/solr/queries/find_by_id_query.rb +1 -1
 - data/lib/valkyrie/persistence/solr/queries/find_members_query.rb +1 -1
 - data/lib/valkyrie/persistence/solr/query_service.rb +12 -12
 - data/lib/valkyrie/persistence/solr/repository.rb +17 -7
 - data/lib/valkyrie/resource/access_controls.rb +1 -1
 - data/lib/valkyrie/resource.rb +0 -1
 - data/lib/valkyrie/specs/shared_specs/change_set.rb +1 -1
 - data/lib/valkyrie/specs/shared_specs/file.rb +1 -0
 - data/lib/valkyrie/specs/shared_specs/persister.rb +22 -4
 - data/lib/valkyrie/specs/shared_specs/queries.rb +7 -0
 - data/lib/valkyrie/specs/shared_specs/resource.rb +1 -1
 - data/lib/valkyrie/specs/shared_specs/storage_adapter.rb +19 -0
 - data/lib/valkyrie/specs/shared_specs/write_only/metadata_adapter.rb +62 -0
 - data/lib/valkyrie/specs/shared_specs.rb +2 -0
 - data/lib/valkyrie/storage/disk.rb +24 -1
 - data/lib/valkyrie/storage/fedora.rb +17 -17
 - data/lib/valkyrie/storage_adapter.rb +12 -12
 - data/lib/valkyrie/types.rb +1 -1
 - data/lib/valkyrie/version.rb +1 -1
 - data/lib/valkyrie/vocab/pcdm_use.rb +12 -0
 - data/lib/valkyrie.rb +13 -27
 - data/tasks/dev.rake +14 -51
 - data/valkyrie.gemspec +3 -6
 - metadata +25 -63
 - data/.docker-stack/valkyrie-development/docker-compose.yml +0 -53
 - data/.docker-stack/valkyrie-test/docker-compose.yml +0 -53
 - data/tasks/docker.rake +0 -31
 
| 
         @@ -48,7 +48,7 @@ module Valkyrie::Persistence::Solr 
     | 
|
| 
       48 
48 
     | 
    
         
             
                # Construct a Time object from the datestamp for the resource creation date indexed in Solr
         
     | 
| 
       49 
49 
     | 
    
         
             
                # @return [Time]
         
     | 
| 
       50 
50 
     | 
    
         
             
                def created_at
         
     | 
| 
       51 
     | 
    
         
            -
                  DateTime.parse(solr_document.fetch("created_at_dtsi").to_s). 
     | 
| 
      
 51 
     | 
    
         
            +
                  DateTime.parse(solr_document.fetch("created_at_dtsi").to_s).new_offset(0)
         
     | 
| 
       52 
52 
     | 
    
         
             
                end
         
     | 
| 
       53 
53 
     | 
    
         | 
| 
       54 
54 
     | 
    
         
             
                # Construct a Time object from the datestamp for the date of the last resource update indexed in Solr
         
     | 
| 
         @@ -79,7 +79,7 @@ module Valkyrie::Persistence::Solr 
     | 
|
| 
       79 
79 
     | 
    
         | 
| 
       80 
80 
     | 
    
         
             
                # Construct the Hash containing the Valkyrie Resource attributes using the Solr Document
         
     | 
| 
       81 
81 
     | 
    
         
             
                # @note this filters for attributes which have been indexed as stored multivalued texts (tsim)
         
     | 
| 
       82 
     | 
    
         
            -
                # @see https://github.com/samvera-labs/valkyrie/blob/ 
     | 
| 
      
 82 
     | 
    
         
            +
                # @see https://github.com/samvera-labs/valkyrie/blob/main/solr/config/schema.xml
         
     | 
| 
       83 
83 
     | 
    
         
             
                # @see https://lucene.apache.org/solr/guide/defining-fields.html#defining-fields
         
     | 
| 
       84 
84 
     | 
    
         
             
                # @return [Hash]
         
     | 
| 
       85 
85 
     | 
    
         
             
                def attribute_hash
         
     | 
| 
         @@ -445,7 +445,7 @@ module Valkyrie::Persistence::Solr 
     | 
|
| 
       445 
445 
     | 
    
         
             
                  # @return [Boolean]
         
     | 
| 
       446 
446 
     | 
    
         
             
                  def self.handles?(value)
         
     | 
| 
       447 
447 
     | 
    
         
             
                    return false unless value.to_s.start_with?("datetime-")
         
     | 
| 
       448 
     | 
    
         
            -
                    DateTime.iso8601(value.sub(/^datetime-/, '')). 
     | 
| 
      
 448 
     | 
    
         
            +
                    DateTime.iso8601(value.sub(/^datetime-/, '')).new_offset(0)
         
     | 
| 
       449 
449 
     | 
    
         
             
                  rescue
         
     | 
| 
       450 
450 
     | 
    
         
             
                    false
         
     | 
| 
       451 
451 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -453,7 +453,7 @@ module Valkyrie::Persistence::Solr 
     | 
|
| 
       453 
453 
     | 
    
         
             
                  # Parses and casts the Solr field value into a UTC DateTime value
         
     | 
| 
       454 
454 
     | 
    
         
             
                  # @return [Time]
         
     | 
| 
       455 
455 
     | 
    
         
             
                  def result
         
     | 
| 
       456 
     | 
    
         
            -
                    DateTime.parse(value.sub(/^datetime-/, '')). 
     | 
| 
      
 456 
     | 
    
         
            +
                    DateTime.parse(value.sub(/^datetime-/, '')).new_offset(0)
         
     | 
| 
       457 
457 
     | 
    
         
             
                  end
         
     | 
| 
       458 
458 
     | 
    
         
             
                end
         
     | 
| 
       459 
459 
     | 
    
         
             
              end
         
     | 
| 
         @@ -6,7 +6,7 @@ module Valkyrie::Persistence::Solr 
     | 
|
| 
       6 
6 
     | 
    
         
             
              # Most methods are delegated to {Valkyrie::Persistence::Solr::Repository}
         
     | 
| 
       7 
7 
     | 
    
         
             
              class Persister
         
     | 
| 
       8 
8 
     | 
    
         
             
                attr_reader :adapter
         
     | 
| 
       9 
     | 
    
         
            -
                delegate :connection, :resource_factory, to: :adapter
         
     | 
| 
      
 9 
     | 
    
         
            +
                delegate :connection, :query_service, :resource_factory, :write_only?, :soft_commit?, to: :adapter
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
11 
     | 
    
         
             
                # @param adapter [Valkyrie::Persistence::Solr::MetadataAdapter] The adapter with the
         
     | 
| 
       12 
12 
     | 
    
         
             
                #   configured solr connection.
         
     | 
| 
         @@ -15,11 +15,23 @@ module Valkyrie::Persistence::Solr 
     | 
|
| 
       15 
15 
     | 
    
         
             
                end
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
       17 
17 
     | 
    
         
             
                # (see Valkyrie::Persistence::Memory::Persister#save)
         
     | 
| 
       18 
     | 
    
         
            -
                 
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
      
 18 
     | 
    
         
            +
                # @return [Boolean] If write_only, whether saving succeeded.
         
     | 
| 
      
 19 
     | 
    
         
            +
                def save(resource:, external_resource: false)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  if write_only?
         
     | 
| 
      
 21 
     | 
    
         
            +
                    repository([resource]).persist
         
     | 
| 
      
 22 
     | 
    
         
            +
                  else
         
     | 
| 
      
 23 
     | 
    
         
            +
                    raise Valkyrie::Persistence::ObjectNotFoundError, "The object #{resource.id} is previously persisted but not found at save time." unless external_resource || valid_for_save?(resource)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    repository([resource]).persist.first
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def valid_for_save?(resource)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  return true unless resource.persisted? # a new resource
         
     | 
| 
      
 30 
     | 
    
         
            +
                  query_service.find_by(id: resource.id).present? # a persisted resource must be found
         
     | 
| 
       20 
31 
     | 
    
         
             
                end
         
     | 
| 
       21 
32 
     | 
    
         | 
| 
       22 
33 
     | 
    
         
             
                # (see Valkyrie::Persistence::Memory::Persister#save_all)
         
     | 
| 
      
 34 
     | 
    
         
            +
                # @return [Boolean] If write_only, whether saving succeeded.
         
     | 
| 
       23 
35 
     | 
    
         
             
                def save_all(resources:)
         
     | 
| 
       24 
36 
     | 
    
         
             
                  repository(resources).persist
         
     | 
| 
       25 
37 
     | 
    
         
             
                end
         
     | 
| 
         @@ -39,7 +51,7 @@ module Valkyrie::Persistence::Solr 
     | 
|
| 
       39 
51 
     | 
    
         
             
                # @param [Array<Valkyrie::Resource>] resources
         
     | 
| 
       40 
52 
     | 
    
         
             
                # @return [Valkyrie::Persistence::Solr::Repository]
         
     | 
| 
       41 
53 
     | 
    
         
             
                def repository(resources)
         
     | 
| 
       42 
     | 
    
         
            -
                  Valkyrie::Persistence::Solr::Repository.new(resources: resources,  
     | 
| 
      
 54 
     | 
    
         
            +
                  Valkyrie::Persistence::Solr::Repository.new(resources: resources, persister: self)
         
     | 
| 
       43 
55 
     | 
    
         
             
                end
         
     | 
| 
       44 
56 
     | 
    
         
             
              end
         
     | 
| 
       45 
57 
     | 
    
         
             
            end
         
     | 
| 
         @@ -32,7 +32,7 @@ module Valkyrie::Persistence::Solr::Queries 
     | 
|
| 
       32 
32 
     | 
    
         
             
                # @note the field used here is alternate_ids_ssim and the value is prefixed by "id-"
         
     | 
| 
       33 
33 
     | 
    
         
             
                # @return [Hash]
         
     | 
| 
       34 
34 
     | 
    
         
             
                def resource
         
     | 
| 
       35 
     | 
    
         
            -
                  connection.get("select", params: { q: "alternate_ids_ssim:\"id-#{alternate_identifier}\"", fl: "*", rows: 1 })["response"]["docs"].first
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @resource ||= connection.get("select", params: { q: "alternate_ids_ssim:\"id-#{alternate_identifier}\"", fl: "*", rows: 1 })["response"]["docs"].first
         
     | 
| 
       36 
36 
     | 
    
         
             
                end
         
     | 
| 
       37 
37 
     | 
    
         
             
              end
         
     | 
| 
       38 
38 
     | 
    
         
             
            end
         
     | 
| 
         @@ -31,7 +31,7 @@ module Valkyrie::Persistence::Solr::Queries 
     | 
|
| 
       31 
31 
     | 
    
         
             
                # Query Solr for for the first document with the ID in a field
         
     | 
| 
       32 
32 
     | 
    
         
             
                # @return [Hash]
         
     | 
| 
       33 
33 
     | 
    
         
             
                def resource
         
     | 
| 
       34 
     | 
    
         
            -
                  connection.get("select", params: { q: "id:\"#{id}\"", fl: "*", rows: 1 })["response"]["docs"].first
         
     | 
| 
      
 34 
     | 
    
         
            +
                  @resource ||= connection.get("select", params: { q: "id:\"#{id}\"", fl: "*", rows: 1 })["response"]["docs"].first
         
     | 
| 
       35 
35 
     | 
    
         
             
                end
         
     | 
| 
       36 
36 
     | 
    
         
             
              end
         
     | 
| 
       37 
37 
     | 
    
         
             
            end
         
     | 
| 
         @@ -27,7 +27,7 @@ module Valkyrie::Persistence::Solr::Queries 
     | 
|
| 
       27 
27 
     | 
    
         
             
                # Results are ordered by the member IDs specified in the Valkyrie Resource attribute
         
     | 
| 
       28 
28 
     | 
    
         
             
                # @yield [Valkyrie::Resource]
         
     | 
| 
       29 
29 
     | 
    
         
             
                def each
         
     | 
| 
       30 
     | 
    
         
            -
                  return []  
     | 
| 
      
 30 
     | 
    
         
            +
                  return [] if resource.id.blank?
         
     | 
| 
       31 
31 
     | 
    
         
             
                  member_ids.map { |id| unordered_members.find { |member| member.id == id } }.reject(&:nil?).each do |member|
         
     | 
| 
       32 
32 
     | 
    
         
             
                    yield member
         
     | 
| 
       33 
33 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -97,19 +97,19 @@ module Valkyrie::Persistence::Solr 
     | 
|
| 
       97 
97 
     | 
    
         | 
| 
       98 
98 
     | 
    
         
             
                private
         
     | 
| 
       99 
99 
     | 
    
         | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
      
 100 
     | 
    
         
            +
                # (see Valkyrie::Persistence::Memory::QueryService#validate_id)
         
     | 
| 
      
 101 
     | 
    
         
            +
                def validate_id(id)
         
     | 
| 
      
 102 
     | 
    
         
            +
                  raise ArgumentError, 'id must be a Valkyrie::ID' unless id.is_a? Valkyrie::ID
         
     | 
| 
      
 103 
     | 
    
         
            +
                end
         
     | 
| 
       104 
104 
     | 
    
         | 
| 
       105 
     | 
    
         
            -
             
     | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
       107 
     | 
    
         
            -
             
     | 
| 
       108 
     | 
    
         
            -
             
     | 
| 
      
 105 
     | 
    
         
            +
                # (see Valkyrie::Persistence::Memory::QueryService#ensure_persisted)
         
     | 
| 
      
 106 
     | 
    
         
            +
                def ensure_persisted(resource)
         
     | 
| 
      
 107 
     | 
    
         
            +
                  raise ArgumentError, 'resource is not saved' unless resource.persisted?
         
     | 
| 
      
 108 
     | 
    
         
            +
                end
         
     | 
| 
       109 
109 
     | 
    
         | 
| 
       110 
     | 
    
         
            -
             
     | 
| 
       111 
     | 
    
         
            -
             
     | 
| 
       112 
     | 
    
         
            -
             
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
      
 110 
     | 
    
         
            +
                # (see Valkyrie::Persistence::Memory::QueryService#ordered_property?)
         
     | 
| 
      
 111 
     | 
    
         
            +
                def ordered_property?(resource:, property:)
         
     | 
| 
      
 112 
     | 
    
         
            +
                  resource.ordered_attribute?(property)
         
     | 
| 
      
 113 
     | 
    
         
            +
                end
         
     | 
| 
       114 
114 
     | 
    
         
             
              end
         
     | 
| 
       115 
115 
     | 
    
         
             
            end
         
     | 
| 
         @@ -3,17 +3,18 @@ module Valkyrie::Persistence::Solr 
     | 
|
| 
       3 
3 
     | 
    
         
             
              # Responsible for handling the logic for persisting or deleting multiple
         
     | 
| 
       4 
4 
     | 
    
         
             
              # objects into or out of solr.
         
     | 
| 
       5 
5 
     | 
    
         
             
              class Repository
         
     | 
| 
       6 
     | 
    
         
            -
                 
     | 
| 
      
 6 
     | 
    
         
            +
                SOFT_COMMIT_PARAMS = { softCommit: true, versions: true }.freeze
         
     | 
| 
      
 7 
     | 
    
         
            +
                NO_COMMIT_PARAMS = { versions: true }.freeze
         
     | 
| 
       7 
8 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
                attr_reader :resources, : 
     | 
| 
      
 9 
     | 
    
         
            +
                attr_reader :resources, :persister
         
     | 
| 
      
 10 
     | 
    
         
            +
                delegate :connection, :resource_factory, :write_only?, :soft_commit?, to: :persister
         
     | 
| 
       9 
11 
     | 
    
         | 
| 
       10 
12 
     | 
    
         
             
                # @param [Array<Valkyrie::Resource>] resources
         
     | 
| 
       11 
13 
     | 
    
         
             
                # @param [RSolr::Client] connection
         
     | 
| 
       12 
14 
     | 
    
         
             
                # @param [ResourceFactory] resource_factory
         
     | 
| 
       13 
     | 
    
         
            -
                def initialize(resources:,  
     | 
| 
      
 15 
     | 
    
         
            +
                def initialize(resources:, persister:)
         
     | 
| 
       14 
16 
     | 
    
         
             
                  @resources = resources
         
     | 
| 
       15 
     | 
    
         
            -
                  @ 
     | 
| 
       16 
     | 
    
         
            -
                  @resource_factory = resource_factory
         
     | 
| 
      
 17 
     | 
    
         
            +
                  @persister = persister
         
     | 
| 
       17 
18 
     | 
    
         
             
                end
         
     | 
| 
       18 
19 
     | 
    
         | 
| 
       19 
20 
     | 
    
         
             
                # Persist the resources into Solr
         
     | 
| 
         @@ -24,6 +25,7 @@ module Valkyrie::Persistence::Solr 
     | 
|
| 
       24 
25 
     | 
    
         
             
                    solr_document(resource)
         
     | 
| 
       25 
26 
     | 
    
         
             
                  end
         
     | 
| 
       26 
27 
     | 
    
         
             
                  results = add_documents(documents)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  return true if write_only?
         
     | 
| 
       27 
29 
     | 
    
         
             
                  versions = results["adds"]&.each_slice(2)&.to_h
         
     | 
| 
       28 
30 
     | 
    
         
             
                  documents.map do |document|
         
     | 
| 
       29 
31 
     | 
    
         
             
                    document["_version_"] = versions.fetch(document[:id])
         
     | 
| 
         @@ -35,7 +37,7 @@ module Valkyrie::Persistence::Solr 
     | 
|
| 
       35 
37 
     | 
    
         
             
                # @return [RSolr::HashWithResponse]
         
     | 
| 
       36 
38 
     | 
    
         
             
                # rubocop:disable Style/IfUnlessModifier
         
     | 
| 
       37 
39 
     | 
    
         
             
                def add_documents(documents)
         
     | 
| 
       38 
     | 
    
         
            -
                  connection.add documents, params:  
     | 
| 
      
 40 
     | 
    
         
            +
                  connection.add documents, params: commit_params
         
     | 
| 
       39 
41 
     | 
    
         
             
                rescue RSolr::Error::Http => exception
         
     | 
| 
       40 
42 
     | 
    
         
             
                  # Error 409 conflict is returned when versions do not match
         
     | 
| 
       41 
43 
     | 
    
         
             
                  if exception.response&.fetch(:status) == 409
         
     | 
| 
         @@ -48,7 +50,7 @@ module Valkyrie::Persistence::Solr 
     | 
|
| 
       48 
50 
     | 
    
         
             
                # Deletes a Solr Document using the ID
         
     | 
| 
       49 
51 
     | 
    
         
             
                # @return [Array<Valkyrie::Resource>] resources which have been deleted from Solr
         
     | 
| 
       50 
52 
     | 
    
         
             
                def delete
         
     | 
| 
       51 
     | 
    
         
            -
                  connection.delete_by_id resources.map { |resource| resource.id.to_s }, params:  
     | 
| 
      
 53 
     | 
    
         
            +
                  connection.delete_by_id resources.map { |resource| resource.id.to_s }, params: commit_params
         
     | 
| 
       52 
54 
     | 
    
         
             
                  resources
         
     | 
| 
       53 
55 
     | 
    
         
             
                end
         
     | 
| 
       54 
56 
     | 
    
         | 
| 
         @@ -75,5 +77,13 @@ module Valkyrie::Persistence::Solr 
     | 
|
| 
       75 
77 
     | 
    
         
             
                  raise Valkyrie::Persistence::StaleObjectError, "One or more resources have been updated by another process." if resources.count > 1
         
     | 
| 
       76 
78 
     | 
    
         
             
                  raise Valkyrie::Persistence::StaleObjectError, "The object #{resources.first.id} has been updated by another process."
         
     | 
| 
       77 
79 
     | 
    
         
             
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                def commit_params
         
     | 
| 
      
 82 
     | 
    
         
            +
                  if persister.soft_commit?
         
     | 
| 
      
 83 
     | 
    
         
            +
                    SOFT_COMMIT_PARAMS
         
     | 
| 
      
 84 
     | 
    
         
            +
                  else
         
     | 
| 
      
 85 
     | 
    
         
            +
                    NO_COMMIT_PARAMS
         
     | 
| 
      
 86 
     | 
    
         
            +
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
                end
         
     | 
| 
       78 
88 
     | 
    
         
             
              end
         
     | 
| 
       79 
89 
     | 
    
         
             
            end
         
     | 
| 
         @@ -11,7 +11,7 @@ module Valkyrie 
     | 
|
| 
       11 
11 
     | 
    
         
             
                #       attribute :nested_resource
         
     | 
| 
       12 
12 
     | 
    
         
             
                #     end
         
     | 
| 
       13 
13 
     | 
    
         
             
                #
         
     | 
| 
       14 
     | 
    
         
            -
                # @see https://github.com/samvera/hydra-head/tree/ 
     | 
| 
      
 14 
     | 
    
         
            +
                # @see https://github.com/samvera/hydra-head/tree/main/hydra-access-controls
         
     | 
| 
       15 
15 
     | 
    
         
             
                # @see lib/valkyrie/indexers/access_controls_indexer/rb
         
     | 
| 
       16 
16 
     | 
    
         
             
                module AccessControls
         
     | 
| 
       17 
17 
     | 
    
         
             
                  def self.included(klass)
         
     | 
    
        data/lib/valkyrie/resource.rb
    CHANGED
    
    | 
         @@ -15,7 +15,6 @@ module Valkyrie 
     | 
|
| 
       15 
15 
     | 
    
         
             
              # @see lib/valkyrie/specs/shared_specs/resource.rb
         
     | 
| 
       16 
16 
     | 
    
         
             
              # rubocop:disable Metrics/ClassLength
         
     | 
| 
       17 
17 
     | 
    
         
             
              class Resource < Dry::Struct
         
     | 
| 
       18 
     | 
    
         
            -
                include Draper::Decoratable
         
     | 
| 
       19 
18 
     | 
    
         
             
                # Allows a Valkyrie::Resource to be instantiated without providing every
         
     | 
| 
       20 
19 
     | 
    
         
             
                # available key, and makes sure the defaults are set up if no value is
         
     | 
| 
       21 
20 
     | 
    
         
             
                # given.
         
     | 
| 
         @@ -75,7 +75,7 @@ RSpec.shared_examples 'a Valkyrie::ChangeSet' do |*_flags| 
     | 
|
| 
       75 
75 
     | 
    
         | 
| 
       76 
76 
     | 
    
         
             
              describe "#optimistic_locking_enabled?" do
         
     | 
| 
       77 
77 
     | 
    
         
             
                it "delegates down to the resource" do
         
     | 
| 
       78 
     | 
    
         
            -
                  expect(change_set.optimistic_locking_enabled?).to eq  
     | 
| 
      
 78 
     | 
    
         
            +
                  expect(change_set.optimistic_locking_enabled?).to eq change_set.resource.optimistic_locking_enabled?
         
     | 
| 
       79 
79 
     | 
    
         
             
                end
         
     | 
| 
       80 
80 
     | 
    
         
             
              end
         
     | 
| 
       81 
81 
     | 
    
         
             
            end
         
     | 
| 
         @@ -9,6 +9,7 @@ RSpec.shared_examples 'a Valkyrie::StorageAdapter::File' do 
     | 
|
| 
       9 
9 
     | 
    
         
             
              it { is_expected.to respond_to(:read) }
         
     | 
| 
       10 
10 
     | 
    
         
             
              it { is_expected.to respond_to(:rewind) }
         
     | 
| 
       11 
11 
     | 
    
         
             
              it { is_expected.to respond_to(:id) }
         
     | 
| 
      
 12 
     | 
    
         
            +
              it { is_expected.to respond_to(:close) }
         
     | 
| 
       12 
13 
     | 
    
         
             
              describe "#disk_path" do
         
     | 
| 
       13 
14 
     | 
    
         
             
                it "returns an existing disk path" do
         
     | 
| 
       14 
15 
     | 
    
         
             
                  expect(File.exist?(file.disk_path)).to eq true
         
     | 
| 
         @@ -50,6 +50,24 @@ RSpec.shared_examples 'a Valkyrie::Persister' do |*flags| 
     | 
|
| 
       50 
50 
     | 
    
         
             
                expect(reloaded.nested_resource.first.title).to eq ["Nested"]
         
     | 
| 
       51 
51 
     | 
    
         
             
              end
         
     | 
| 
       52 
52 
     | 
    
         | 
| 
      
 53 
     | 
    
         
            +
              context "when a persisted resource is not in the database" do
         
     | 
| 
      
 54 
     | 
    
         
            +
                it "throws an ObjectNotFoundError" do
         
     | 
| 
      
 55 
     | 
    
         
            +
                  expect(resource).not_to be_persisted
         
     | 
| 
      
 56 
     | 
    
         
            +
                  saved = persister.save(resource: resource)
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                  expect(saved).to be_persisted
         
     | 
| 
      
 59 
     | 
    
         
            +
                  persister.delete(resource: saved)
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                  expect { persister.save(resource: saved) }.to raise_error(Valkyrie::Persistence::ObjectNotFoundError)
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
                it "is okay if it's from another persister" do
         
     | 
| 
      
 64 
     | 
    
         
            +
                  memory_adapter = Valkyrie::Persistence::Memory::MetadataAdapter.new
         
     | 
| 
      
 65 
     | 
    
         
            +
                  saved = memory_adapter.persister.save(resource: resource)
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                  expect { persister.save(resource: saved, external_resource: true) }.not_to raise_error
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
              end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
       53 
71 
     | 
    
         
             
              it "can persist single values" do
         
     | 
| 
       54 
72 
     | 
    
         
             
                resource.single_value = "A single value"
         
     | 
| 
       55 
73 
     | 
    
         | 
| 
         @@ -194,9 +212,9 @@ RSpec.shared_examples 'a Valkyrie::Persister' do |*flags| 
     | 
|
| 
       194 
212 
     | 
    
         
             
                reloaded = query_service.find_by(id: book.id)
         
     | 
| 
       195 
213 
     | 
    
         | 
| 
       196 
214 
     | 
    
         
             
                expect(reloaded.title.first.to_i).to eq(time1.to_i)
         
     | 
| 
       197 
     | 
    
         
            -
                expect(reloaded.title.first.zone).to eq(' 
     | 
| 
      
 215 
     | 
    
         
            +
                expect(reloaded.title.first.zone).to eq('+00:00')
         
     | 
| 
       198 
216 
     | 
    
         
             
                expect(reloaded.author.first.to_i).to eq(time2.to_i)
         
     | 
| 
       199 
     | 
    
         
            -
                expect(reloaded.author.first.zone).to eq(' 
     | 
| 
      
 217 
     | 
    
         
            +
                expect(reloaded.author.first.zone).to eq('+00:00')
         
     | 
| 
       200 
218 
     | 
    
         
             
                expect(reloaded.other_author.first).to eq "2019-01"
         
     | 
| 
       201 
219 
     | 
    
         
             
              end
         
     | 
| 
       202 
220 
     | 
    
         | 
| 
         @@ -351,7 +369,7 @@ RSpec.shared_examples 'a Valkyrie::Persister' do |*flags| 
     | 
|
| 
       351 
369 
     | 
    
         
             
                      # update the resource in the datastore to make its token stale
         
     | 
| 
       352 
370 
     | 
    
         
             
                      persister.save(resource: resource)
         
     | 
| 
       353 
371 
     | 
    
         | 
| 
       354 
     | 
    
         
            -
                      expect { persister.save(resource: resource) }.to raise_error(Valkyrie::Persistence::StaleObjectError 
     | 
| 
      
 372 
     | 
    
         
            +
                      expect { persister.save(resource: resource) }.to raise_error(Valkyrie::Persistence::StaleObjectError)
         
     | 
| 
       355 
373 
     | 
    
         
             
                    end
         
     | 
| 
       356 
374 
     | 
    
         
             
                  end
         
     | 
| 
       357 
375 
     | 
    
         | 
| 
         @@ -425,7 +443,7 @@ RSpec.shared_examples 'a Valkyrie::Persister' do |*flags| 
     | 
|
| 
       425 
443 
     | 
    
         
             
                      persister.save(resource: resource2)
         
     | 
| 
       426 
444 
     | 
    
         | 
| 
       427 
445 
     | 
    
         
             
                      expect { persister.save_all(resources: [resource1, resource2, resource3]) }
         
     | 
| 
       428 
     | 
    
         
            -
                        .to raise_error(Valkyrie::Persistence::StaleObjectError 
     | 
| 
      
 446 
     | 
    
         
            +
                        .to raise_error(Valkyrie::Persistence::StaleObjectError)
         
     | 
| 
       429 
447 
     | 
    
         
             
                    end
         
     | 
| 
       430 
448 
     | 
    
         
             
                  end
         
     | 
| 
       431 
449 
     | 
    
         
             
                end
         
     | 
| 
         @@ -464,6 +464,13 @@ RSpec.shared_examples 'a Valkyrie query provider' do 
     | 
|
| 
       464 
464 
     | 
    
         
             
                end
         
     | 
| 
       465 
465 
     | 
    
         
             
              end
         
     | 
| 
       466 
466 
     | 
    
         | 
| 
      
 467 
     | 
    
         
            +
              describe ".custom_queries" do
         
     | 
| 
      
 468 
     | 
    
         
            +
                it "raises NoMethodError when the custom query does not exist" do
         
     | 
| 
      
 469 
     | 
    
         
            +
                  expect(query_service.custom_queries).not_to respond_to :very_fake_query
         
     | 
| 
      
 470 
     | 
    
         
            +
                  expect { query_service.custom_queries.very_fake_query }.to raise_error(NoMethodError)
         
     | 
| 
      
 471 
     | 
    
         
            +
                end
         
     | 
| 
      
 472 
     | 
    
         
            +
              end
         
     | 
| 
      
 473 
     | 
    
         
            +
             
     | 
| 
       467 
474 
     | 
    
         
             
              describe ".register_query_handler" do
         
     | 
| 
       468 
475 
     | 
    
         
             
                it "can register a query handler" do
         
     | 
| 
       469 
476 
     | 
    
         
             
                  class QueryHandler
         
     | 
| 
         @@ -30,6 +30,25 @@ RSpec.shared_examples 'a Valkyrie::StorageAdapter' do 
     | 
|
| 
       30 
30 
     | 
    
         
             
                expect(uploaded_file.valid?(digests: { sha1: sha1 })).to be true
         
     | 
| 
       31 
31 
     | 
    
         
             
              end
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
      
 33 
     | 
    
         
            +
              it "doesn't leave a file handle open on upload/find_by" do
         
     | 
| 
      
 34 
     | 
    
         
            +
                # No file handle left open from upload.
         
     | 
| 
      
 35 
     | 
    
         
            +
                resource = Valkyrie::Specs::CustomResource.new(id: "testdiscovery")
         
     | 
| 
      
 36 
     | 
    
         
            +
                pre_open_files = open_files
         
     | 
| 
      
 37 
     | 
    
         
            +
                uploaded_file = storage_adapter.upload(file: file, original_filename: 'foo.jpg', resource: resource, fake_upload_argument: true)
         
     | 
| 
      
 38 
     | 
    
         
            +
                file.close
         
     | 
| 
      
 39 
     | 
    
         
            +
                expect(pre_open_files.size).to eq open_files.size
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                # No file handle left open from find_by
         
     | 
| 
      
 42 
     | 
    
         
            +
                pre_open_files = open_files
         
     | 
| 
      
 43 
     | 
    
         
            +
                the_file = storage_adapter.find_by(id: uploaded_file.id)
         
     | 
| 
      
 44 
     | 
    
         
            +
                expect(the_file).to be_kind_of Valkyrie::StorageAdapter::File
         
     | 
| 
      
 45 
     | 
    
         
            +
                expect(pre_open_files.size).to eq open_files.size
         
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
              def open_files
         
     | 
| 
      
 49 
     | 
    
         
            +
                `lsof +D . | awk '{print $9}'`.split.uniq[1..-1]
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
       33 
52 
     | 
    
         
             
              it "can upload, validate, re-fetch, and delete a file" do
         
     | 
| 
       34 
53 
     | 
    
         
             
                resource = Valkyrie::Specs::CustomResource.new(id: "test")
         
     | 
| 
       35 
54 
     | 
    
         
             
                sha1 = Digest::SHA1.file(file).to_s
         
     | 
| 
         @@ -0,0 +1,62 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
            RSpec.shared_examples 'a write-only Valkyrie::MetadataAdapter' do |passed_adapter|
         
     | 
| 
      
 3 
     | 
    
         
            +
              before do
         
     | 
| 
      
 4 
     | 
    
         
            +
                raise 'adapter must be set with `let(:adapter)`' unless
         
     | 
| 
      
 5 
     | 
    
         
            +
                  defined? adapter
         
     | 
| 
      
 6 
     | 
    
         
            +
              end
         
     | 
| 
      
 7 
     | 
    
         
            +
              subject { passed_adapter || adapter }
         
     | 
| 
      
 8 
     | 
    
         
            +
              let(:persister) { adapter.persister }
         
     | 
| 
      
 9 
     | 
    
         
            +
              it { is_expected.to respond_to(:persister).with(0).arguments }
         
     | 
| 
      
 10 
     | 
    
         
            +
              it { is_expected.to respond_to(:id).with(0).arguments }
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              describe "#id" do
         
     | 
| 
      
 13 
     | 
    
         
            +
                it "is a valid string representation of an MD5 hash" do
         
     | 
| 
      
 14 
     | 
    
         
            +
                  expect(adapter.id).to be_a Valkyrie::ID
         
     | 
| 
      
 15 
     | 
    
         
            +
                  expect(adapter.id.to_s.length).to eq 32
         
     | 
| 
      
 16 
     | 
    
         
            +
                  expect(adapter.id.to_s).to match(/^[a-f,0-9]+$/)
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              describe "#write_only?" do
         
     | 
| 
      
 21 
     | 
    
         
            +
                it "returns true" do
         
     | 
| 
      
 22 
     | 
    
         
            +
                  expect(adapter).to be_write_only
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              describe "persister" do
         
     | 
| 
      
 27 
     | 
    
         
            +
                before do
         
     | 
| 
      
 28 
     | 
    
         
            +
                  class WriteOnlyCustomResource < Valkyrie::Resource
         
     | 
| 
      
 29 
     | 
    
         
            +
                    include Valkyrie::Resource::AccessControls
         
     | 
| 
      
 30 
     | 
    
         
            +
                    attribute :title
         
     | 
| 
      
 31 
     | 
    
         
            +
                    attribute :author
         
     | 
| 
      
 32 
     | 
    
         
            +
                    attribute :other_author
         
     | 
| 
      
 33 
     | 
    
         
            +
                    attribute :member_ids
         
     | 
| 
      
 34 
     | 
    
         
            +
                    attribute :nested_resource
         
     | 
| 
      
 35 
     | 
    
         
            +
                    attribute :single_value, Valkyrie::Types::String.optional
         
     | 
| 
      
 36 
     | 
    
         
            +
                    attribute :ordered_authors, Valkyrie::Types::Array.of(Valkyrie::Types::Anything).meta(ordered: true)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    attribute :ordered_nested, Valkyrie::Types::Array.of(WriteOnlyCustomResource).meta(ordered: true)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
                after do
         
     | 
| 
      
 41 
     | 
    
         
            +
                  Object.send(:remove_const, :WriteOnlyCustomResource)
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                subject { persister }
         
     | 
| 
      
 45 
     | 
    
         
            +
                let(:resource_class) { WriteOnlyCustomResource }
         
     | 
| 
      
 46 
     | 
    
         
            +
                let(:resource) { resource_class.new }
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                it { is_expected.to respond_to(:save).with_keywords(:resource) }
         
     | 
| 
      
 49 
     | 
    
         
            +
                it { is_expected.to respond_to(:save_all).with_keywords(:resources) }
         
     | 
| 
      
 50 
     | 
    
         
            +
                it { is_expected.to respond_to(:delete).with_keywords(:resource) }
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                it "can save a resource" do
         
     | 
| 
      
 53 
     | 
    
         
            +
                  expect(persister.save(resource: resource)).to eq true
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                it "can save multiple resources at once" do
         
     | 
| 
      
 57 
     | 
    
         
            +
                  resource2 = resource_class.new
         
     | 
| 
      
 58 
     | 
    
         
            +
                  results = persister.save_all(resources: [resource, resource2])
         
     | 
| 
      
 59 
     | 
    
         
            +
                  expect(results).to eq true
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -13,3 +13,5 @@ require 'valkyrie/specs/shared_specs/change_set_persister.rb' 
     | 
|
| 
       13 
13 
     | 
    
         
             
            require 'valkyrie/specs/shared_specs/file.rb'
         
     | 
| 
       14 
14 
     | 
    
         
             
            require 'valkyrie/specs/shared_specs/change_set.rb'
         
     | 
| 
       15 
15 
     | 
    
         
             
            require 'valkyrie/specs/shared_specs/solr_indexer.rb'
         
     | 
| 
      
 16 
     | 
    
         
            +
            # Write-only tests.
         
     | 
| 
      
 17 
     | 
    
         
            +
            require 'valkyrie/specs/shared_specs/write_only/metadata_adapter.rb'
         
     | 
| 
         @@ -36,11 +36,34 @@ module Valkyrie::Storage 
     | 
|
| 
       36 
36 
     | 
    
         
             
                # @return [Valkyrie::StorageAdapter::File]
         
     | 
| 
       37 
37 
     | 
    
         
             
                # @raise Valkyrie::StorageAdapter::FileNotFound if nothing is found
         
     | 
| 
       38 
38 
     | 
    
         
             
                def find_by(id:)
         
     | 
| 
       39 
     | 
    
         
            -
                  Valkyrie::StorageAdapter::File.new(id: Valkyrie::ID.new(id.to_s), io:  
     | 
| 
      
 39 
     | 
    
         
            +
                  Valkyrie::StorageAdapter::File.new(id: Valkyrie::ID.new(id.to_s), io: LazyFile.open(file_path(id), 'rb'))
         
     | 
| 
       40 
40 
     | 
    
         
             
                rescue Errno::ENOENT
         
     | 
| 
       41 
41 
     | 
    
         
             
                  raise Valkyrie::StorageAdapter::FileNotFound
         
     | 
| 
       42 
42 
     | 
    
         
             
                end
         
     | 
| 
       43 
43 
     | 
    
         | 
| 
      
 44 
     | 
    
         
            +
                ## LazyFile takes File.open parameters but doesn't leave a file handle open on
         
     | 
| 
      
 45 
     | 
    
         
            +
                # instantiation. This way StorageAdapter#find_by doesn't open a handle
         
     | 
| 
      
 46 
     | 
    
         
            +
                # silently and never clean up after itself.
         
     | 
| 
      
 47 
     | 
    
         
            +
                class LazyFile
         
     | 
| 
      
 48 
     | 
    
         
            +
                  def self.open(path, mode)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    # Open the file regularly and close it, so it can error if it doesn't
         
     | 
| 
      
 50 
     | 
    
         
            +
                    # exist.
         
     | 
| 
      
 51 
     | 
    
         
            +
                    File.open(path, mode).close
         
     | 
| 
      
 52 
     | 
    
         
            +
                    new(path, mode)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                  delegate(*(File.instance_methods - Object.instance_methods), to: :_inner_file)
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  def initialize(path, mode)
         
     | 
| 
      
 58 
     | 
    
         
            +
                    @__path = path
         
     | 
| 
      
 59 
     | 
    
         
            +
                    @__mode = mode
         
     | 
| 
      
 60 
     | 
    
         
            +
                  end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  def _inner_file
         
     | 
| 
      
 63 
     | 
    
         
            +
                    @_inner_file ||= File.open(@__path, @__mode)
         
     | 
| 
      
 64 
     | 
    
         
            +
                  end
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
       44 
67 
     | 
    
         
             
                # Delete the file on disk associated with the given identifier.
         
     | 
| 
       45 
68 
     | 
    
         
             
                # @param id [Valkyrie::ID]
         
     | 
| 
       46 
69 
     | 
    
         
             
                def delete(id:)
         
     | 
| 
         @@ -37,7 +37,7 @@ module Valkyrie::Storage 
     | 
|
| 
       37 
37 
     | 
    
         
             
                def upload(file:, original_filename:, resource:, content_type: "application/octet-stream", # rubocop:disable Metrics/ParameterLists
         
     | 
| 
       38 
38 
     | 
    
         
             
                           resource_uri_transformer: default_resource_uri_transformer, **_extra_arguments)
         
     | 
| 
       39 
39 
     | 
    
         
             
                  identifier = resource_uri_transformer.call(resource, base_url) + '/original'
         
     | 
| 
       40 
     | 
    
         
            -
                  sha1 =  
     | 
| 
      
 40 
     | 
    
         
            +
                  sha1 = [5, 6].include?(fedora_version) ? "sha" : "sha1"
         
     | 
| 
       41 
41 
     | 
    
         
             
                  connection.http.put do |request|
         
     | 
| 
       42 
42 
     | 
    
         
             
                    request.url identifier
         
     | 
| 
       43 
43 
     | 
    
         
             
                    request.headers['Content-Type'] = content_type
         
     | 
| 
         @@ -83,24 +83,24 @@ module Valkyrie::Storage 
     | 
|
| 
       83 
83 
     | 
    
         | 
| 
       84 
84 
     | 
    
         
             
                private
         
     | 
| 
       85 
85 
     | 
    
         | 
| 
       86 
     | 
    
         
            -
             
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
      
 86 
     | 
    
         
            +
                # @return [IOProxy]
         
     | 
| 
      
 87 
     | 
    
         
            +
                def response(id:)
         
     | 
| 
      
 88 
     | 
    
         
            +
                  response = connection.http.get(fedora_identifier(id: id))
         
     | 
| 
      
 89 
     | 
    
         
            +
                  raise Valkyrie::StorageAdapter::FileNotFound unless response.success?
         
     | 
| 
      
 90 
     | 
    
         
            +
                  IOProxy.new(response.body)
         
     | 
| 
      
 91 
     | 
    
         
            +
                end
         
     | 
| 
       92 
92 
     | 
    
         | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
       95 
     | 
    
         
            -
             
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
                    end
         
     | 
| 
      
 93 
     | 
    
         
            +
                def default_resource_uri_transformer
         
     | 
| 
      
 94 
     | 
    
         
            +
                  lambda do |resource, base_url|
         
     | 
| 
      
 95 
     | 
    
         
            +
                    id = CGI.escape(resource.id.to_s)
         
     | 
| 
      
 96 
     | 
    
         
            +
                    RDF::URI.new(base_url + id)
         
     | 
| 
       98 
97 
     | 
    
         
             
                  end
         
     | 
| 
      
 98 
     | 
    
         
            +
                end
         
     | 
| 
       99 
99 
     | 
    
         | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
     | 
    
         
            -
             
     | 
| 
      
 100 
     | 
    
         
            +
                def base_url
         
     | 
| 
      
 101 
     | 
    
         
            +
                  pre_divider = base_path.starts_with?(SLASH) ? '' : SLASH
         
     | 
| 
      
 102 
     | 
    
         
            +
                  post_divider = base_path.ends_with?(SLASH) ? '' : SLASH
         
     | 
| 
      
 103 
     | 
    
         
            +
                  "#{connection.http.url_prefix}#{pre_divider}#{base_path}#{post_divider}"
         
     | 
| 
      
 104 
     | 
    
         
            +
                end
         
     | 
| 
       105 
105 
     | 
    
         
             
              end
         
     | 
| 
       106 
106 
     | 
    
         
             
            end
         
     | 
| 
         @@ -67,7 +67,7 @@ module Valkyrie 
     | 
|
| 
       67 
67 
     | 
    
         
             
                class File < Dry::Struct
         
     | 
| 
       68 
68 
     | 
    
         
             
                  attribute :id, Valkyrie::Types::Any
         
     | 
| 
       69 
69 
     | 
    
         
             
                  attribute :io, Valkyrie::Types::Any
         
     | 
| 
       70 
     | 
    
         
            -
                  delegate :size, :read, :rewind, to: :io
         
     | 
| 
      
 70 
     | 
    
         
            +
                  delegate :size, :read, :rewind, :close, to: :io
         
     | 
| 
       71 
71 
     | 
    
         
             
                  def stream
         
     | 
| 
       72 
72 
     | 
    
         
             
                    io
         
     | 
| 
       73 
73 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -106,20 +106,20 @@ module Valkyrie 
     | 
|
| 
       106 
106 
     | 
    
         | 
| 
       107 
107 
     | 
    
         
             
                  private
         
     | 
| 
       108 
108 
     | 
    
         | 
| 
       109 
     | 
    
         
            -
             
     | 
| 
       110 
     | 
    
         
            -
             
     | 
| 
       111 
     | 
    
         
            -
             
     | 
| 
      
 109 
     | 
    
         
            +
                  def tmp_file_name
         
     | 
| 
      
 110 
     | 
    
         
            +
                    id.to_s.tr(':/', '__')
         
     | 
| 
      
 111 
     | 
    
         
            +
                  end
         
     | 
| 
       112 
112 
     | 
    
         | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
             
     | 
| 
       115 
     | 
    
         
            -
             
     | 
| 
      
 113 
     | 
    
         
            +
                  def tmp_file_path
         
     | 
| 
      
 114 
     | 
    
         
            +
                    ::File.join(Dir.tmpdir, tmp_file_name)
         
     | 
| 
      
 115 
     | 
    
         
            +
                  end
         
     | 
| 
       116 
116 
     | 
    
         | 
| 
       117 
     | 
    
         
            -
             
     | 
| 
       118 
     | 
    
         
            -
             
     | 
| 
       119 
     | 
    
         
            -
             
     | 
| 
       120 
     | 
    
         
            -
             
     | 
| 
       121 
     | 
    
         
            -
                      end
         
     | 
| 
      
 117 
     | 
    
         
            +
                  def tmp_file
         
     | 
| 
      
 118 
     | 
    
         
            +
                    @tmp_file ||= ::File.open(tmp_file_path, 'w+b') do |f|
         
     | 
| 
      
 119 
     | 
    
         
            +
                      IO.copy_stream(io, f)
         
     | 
| 
      
 120 
     | 
    
         
            +
                      f
         
     | 
| 
       122 
121 
     | 
    
         
             
                    end
         
     | 
| 
      
 122 
     | 
    
         
            +
                  end
         
     | 
| 
       123 
123 
     | 
    
         
             
                end
         
     | 
| 
       124 
124 
     | 
    
         
             
              end
         
     | 
| 
       125 
125 
     | 
    
         
             
            end
         
     | 
    
        data/lib/valkyrie/types.rb
    CHANGED
    
    | 
         @@ -84,7 +84,7 @@ module Valkyrie 
     | 
|
| 
       84 
84 
     | 
    
         
             
                Set = Array.constructor do |value|
         
     | 
| 
       85 
85 
     | 
    
         
             
                  value = Array[value]
         
     | 
| 
       86 
86 
     | 
    
         
             
                  clean_values = value.reject do |val|
         
     | 
| 
       87 
     | 
    
         
            -
                     
     | 
| 
      
 87 
     | 
    
         
            +
                    (val.is_a?(Valkyrie::ID) && val.to_s == '') || val == ''
         
     | 
| 
       88 
88 
     | 
    
         
             
                  end.reject(&:nil?).uniq
         
     | 
| 
       89 
89 
     | 
    
         | 
| 
       90 
90 
     | 
    
         
             
                  clean_values.map do |val|
         
     | 
    
        data/lib/valkyrie/version.rb
    CHANGED
    
    
| 
         @@ -39,10 +39,22 @@ module Valkyrie::Vocab 
     | 
|
| 
       39 
39 
     | 
    
         
             
                     "rdf:subClassOf": %(http://pcdm.org/resources#File),
         
     | 
| 
       40 
40 
     | 
    
         
             
                     "rdfs:isDefinedBy": %(pcdmuse:),
         
     | 
| 
       41 
41 
     | 
    
         
             
                     type: "rdfs:Class"
         
     | 
| 
      
 42 
     | 
    
         
            +
                term :PreservationFile,
         
     | 
| 
      
 43 
     | 
    
         
            +
                     comment: %(Best quality representation of the Object appropriate for long-term
         
     | 
| 
      
 44 
     | 
    
         
            +
                       preservation.),
         
     | 
| 
      
 45 
     | 
    
         
            +
                     label: "preservation file",
         
     | 
| 
      
 46 
     | 
    
         
            +
                     "dct:replaces": %(http://pcdm.org/use#PreservationMasterFile),
         
     | 
| 
      
 47 
     | 
    
         
            +
                     "rdf:subClassOf": %(http://pcdm.org/resources#File),
         
     | 
| 
      
 48 
     | 
    
         
            +
                     "rdfs:isDefinedBy": %(pcdmuse:),
         
     | 
| 
      
 49 
     | 
    
         
            +
                     type: "rdfs:Class"
         
     | 
| 
      
 50 
     | 
    
         
            +
                warn "[DEPRECATION] PCDM is deprecating '#{self.class}#PreservationMasterFile'. Use #{self.class}#PreservationFile instead."
         
     | 
| 
      
 51 
     | 
    
         
            +
                # @deprecated
         
     | 
| 
       42 
52 
     | 
    
         
             
                term :PreservationMasterFile,
         
     | 
| 
       43 
53 
     | 
    
         
             
                     comment: %(Best quality representation of the Object appropriate for long-term
         
     | 
| 
       44 
54 
     | 
    
         
             
                       preservation.),
         
     | 
| 
       45 
55 
     | 
    
         
             
                     label: "preservation master file",
         
     | 
| 
      
 56 
     | 
    
         
            +
                     "dct:isReplacedBy": %(http://pcdm.org/use#PreservationFile),
         
     | 
| 
      
 57 
     | 
    
         
            +
                     "owl:deprecated": true,
         
     | 
| 
       46 
58 
     | 
    
         
             
                     "rdf:subClassOf": %(http://pcdm.org/resources#File),
         
     | 
| 
       47 
59 
     | 
    
         
             
                     "rdfs:isDefinedBy": %(pcdmuse:),
         
     | 
| 
       48 
60 
     | 
    
         
             
                     type: "rdfs:Class"
         
     | 
    
        data/lib/valkyrie.rb
    CHANGED
    
    | 
         @@ -5,7 +5,6 @@ require 'active_support' 
     | 
|
| 
       5 
5 
     | 
    
         
             
            require 'active_support/core_ext'
         
     | 
| 
       6 
6 
     | 
    
         
             
            require 'dry-types'
         
     | 
| 
       7 
7 
     | 
    
         
             
            require 'dry-struct'
         
     | 
| 
       8 
     | 
    
         
            -
            require 'draper'
         
     | 
| 
       9 
8 
     | 
    
         
             
            require 'reform'
         
     | 
| 
       10 
9 
     | 
    
         
             
            require 'rdf'
         
     | 
| 
       11 
10 
     | 
    
         
             
            require 'valkyrie/rdf_patches'
         
     | 
| 
         @@ -87,19 +86,6 @@ module Valkyrie 
     | 
|
| 
       87 
86 
     | 
    
         
             
                  Valkyrie::StorageAdapter.find(super.to_sym)
         
     | 
| 
       88 
87 
     | 
    
         
             
                end
         
     | 
| 
       89 
88 
     | 
    
         | 
| 
       90 
     | 
    
         
            -
                # @api public
         
     | 
| 
       91 
     | 
    
         
            -
                # Configure id_string_equality to be true in order to make Valkyrie::ID
         
     | 
| 
       92 
     | 
    
         
            -
                # equal to the string value they contain. This will be the default behavior
         
     | 
| 
       93 
     | 
    
         
            -
                # in v3.0.0.
         
     | 
| 
       94 
     | 
    
         
            -
                #
         
     | 
| 
       95 
     | 
    
         
            -
                # @return [Boolean] Whether `Valkyrie::ID` should be equal to their string counterpart.
         
     | 
| 
       96 
     | 
    
         
            -
                def id_string_equality
         
     | 
| 
       97 
     | 
    
         
            -
                  super
         
     | 
| 
       98 
     | 
    
         
            -
                end
         
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
                # @!attribute [w] id_string_equality=
         
     | 
| 
       101 
     | 
    
         
            -
                #   The setter for #id_string_equality; see it's implementation
         
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
89 
     | 
    
         
             
                # @api public
         
     | 
| 
       104 
90 
     | 
    
         
             
                #
         
     | 
| 
       105 
91 
     | 
    
         
             
                # The returned anonymous method (e.g. responds to #call) has a signature of
         
     | 
| 
         @@ -119,19 +105,19 @@ module Valkyrie 
     | 
|
| 
       119 
105 
     | 
    
         | 
| 
       120 
106 
     | 
    
         
             
                private
         
     | 
| 
       121 
107 
     | 
    
         | 
| 
       122 
     | 
    
         
            -
             
     | 
| 
       123 
     | 
    
         
            -
             
     | 
| 
       124 
     | 
    
         
            -
             
     | 
| 
       125 
     | 
    
         
            -
             
     | 
| 
       126 
     | 
    
         
            -
             
     | 
| 
       127 
     | 
    
         
            -
             
     | 
| 
       128 
     | 
    
         
            -
             
     | 
| 
       129 
     | 
    
         
            -
             
     | 
| 
       130 
     | 
    
         
            -
             
     | 
| 
       131 
     | 
    
         
            -
             
     | 
| 
       132 
     | 
    
         
            -
             
     | 
| 
       133 
     | 
    
         
            -
             
     | 
| 
       134 
     | 
    
         
            -
             
     | 
| 
      
 108 
     | 
    
         
            +
                def defaults
         
     | 
| 
      
 109 
     | 
    
         
            +
                  {
         
     | 
| 
      
 110 
     | 
    
         
            +
                    resource_class_resolver: method(:default_resource_class_resolver)
         
     | 
| 
      
 111 
     | 
    
         
            +
                  }
         
     | 
| 
      
 112 
     | 
    
         
            +
                end
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                # String constantize is a "by convention" factory. This works, but assumes
         
     | 
| 
      
 115 
     | 
    
         
            +
                # the ruby class once used to persist is the model used to now reify.
         
     | 
| 
      
 116 
     | 
    
         
            +
                #
         
     | 
| 
      
 117 
     | 
    
         
            +
                # @param [String] class_name
         
     | 
| 
      
 118 
     | 
    
         
            +
                def default_resource_class_resolver(class_name)
         
     | 
| 
      
 119 
     | 
    
         
            +
                  class_name.constantize
         
     | 
| 
      
 120 
     | 
    
         
            +
                end
         
     | 
| 
       135 
121 
     | 
    
         
             
              end
         
     | 
| 
       136 
122 
     | 
    
         | 
| 
       137 
123 
     | 
    
         
             
              module_function :config, :logger, :logger=, :config_root_path, :environment, :config_file, :config_hash
         
     |