hyrax 3.0.0.pre.beta1 → 3.0.0.pre.beta2

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.
Files changed (170) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +157 -68
  3. data/.travis.yml +4 -1
  4. data/Gemfile +1 -0
  5. data/README.md +3 -3
  6. data/app/actors/hyrax/actors/collections_membership_actor.rb +5 -55
  7. data/app/actors/hyrax/actors/create_with_remote_files_ordered_members_actor.rb +6 -8
  8. data/app/actors/hyrax/actors/environment.rb +15 -0
  9. data/app/actors/hyrax/actors/interpret_visibility_actor.rb +22 -37
  10. data/app/assets/javascripts/hyrax/editor/controlled_vocabulary.es6 +1 -1
  11. data/app/assets/stylesheets/hyrax/_collections.scss +5 -3
  12. data/app/assets/stylesheets/hyrax/dashboard.scss +3 -3
  13. data/app/controllers/concerns/hyrax/works_controller_behavior.rb +21 -2
  14. data/app/controllers/hyrax/homepage_controller.rb +1 -1
  15. data/app/forms/hyrax/forms/work_form.rb +1 -1
  16. data/app/helpers/hyrax/collections_helper.rb +13 -0
  17. data/app/helpers/hyrax/hyrax_helper_behavior.rb +3 -3
  18. data/app/indexers/hyrax/admin_set_indexer.rb +1 -1
  19. data/app/indexers/hyrax/basic_metadata_indexer.rb +1 -1
  20. data/app/indexers/hyrax/collection_indexer.rb +3 -3
  21. data/app/indexers/hyrax/deep_indexing_service.rb +12 -12
  22. data/app/indexers/hyrax/file_set_indexer.rb +1 -1
  23. data/app/indexers/hyrax/indexes_workflow.rb +4 -4
  24. data/app/indexers/hyrax/work_indexer.rb +1 -1
  25. data/app/models/concerns/hyrax/basic_metadata.rb +2 -0
  26. data/app/models/concerns/hyrax/collection_behavior.rb +3 -3
  27. data/app/models/concerns/hyrax/file_set/querying.rb +1 -1
  28. data/app/models/concerns/hyrax/human_readable_type.rb +2 -2
  29. data/app/models/concerns/hyrax/solr_document/characterization.rb +23 -23
  30. data/app/models/concerns/hyrax/solr_document/metadata.rb +3 -2
  31. data/app/models/concerns/hyrax/solr_document_behavior.rb +3 -3
  32. data/app/models/concerns/hyrax/user.rb +10 -2
  33. data/app/presenters/hyrax/work_show_presenter.rb +2 -2
  34. data/app/renderers/hyrax/renderers/faceted_attribute_renderer.rb +1 -1
  35. data/app/search_builders/hyrax/collection_search_builder.rb +1 -1
  36. data/app/search_builders/hyrax/deposit_search_builder.rb +1 -1
  37. data/app/search_builders/hyrax/embargo_search_builder.rb +1 -1
  38. data/app/search_builders/hyrax/lease_search_builder.rb +1 -1
  39. data/app/services/hyrax/default_middleware_stack.rb +0 -4
  40. data/app/services/hyrax/statistics/file_sets/by_format.rb +1 -1
  41. data/app/services/hyrax/statistics/works/by_resource_type.rb +1 -1
  42. data/app/services/hyrax/visibility_intention.rb +78 -0
  43. data/app/views/catalog/_index_list_default.html.erb +3 -3
  44. data/app/views/catalog/_thumbnail_list_collection.html.erb +3 -2
  45. data/app/views/hyrax/base/_attribute_rows.html.erb +1 -0
  46. data/app/views/hyrax/base/_form_files.html.erb +2 -2
  47. data/app/views/hyrax/base/_form_visibility_component.html.erb +1 -1
  48. data/app/views/hyrax/base/_show_actions.html.erb +6 -6
  49. data/app/views/hyrax/base/show.html.erb +2 -2
  50. data/app/views/hyrax/batch_edits/_check_all.html.erb +1 -1
  51. data/app/views/hyrax/batch_edits/_delete_selected.html.erb +1 -1
  52. data/app/views/hyrax/collections/_show_document_list_row.html.erb +1 -1
  53. data/app/views/hyrax/dashboard/collections/_show_document_list_row.html.erb +1 -1
  54. data/app/views/hyrax/dashboard/show_admin.html.erb +4 -4
  55. data/app/views/records/show_fields/_based_near.html.erb +1 -1
  56. data/app/views/records/show_fields/_creator.html.erb +1 -1
  57. data/app/views/records/show_fields/_keyword.html.erb +1 -1
  58. data/app/views/records/show_fields/_language.html.erb +1 -1
  59. data/app/views/records/show_fields/_publisher.html.erb +1 -1
  60. data/app/views/records/show_fields/_resource_type.html.erb +1 -1
  61. data/app/views/records/show_fields/_subject.html.erb +1 -1
  62. data/config/initializers/samvera-nesting_indexer_initializer.rb +3 -3
  63. data/config/locales/hyrax.de.yml +35 -22
  64. data/config/locales/hyrax.en.yml +22 -2
  65. data/config/locales/hyrax.es.yml +21 -1
  66. data/config/locales/hyrax.fr.yml +21 -1
  67. data/config/locales/hyrax.it.yml +21 -1
  68. data/config/locales/hyrax.pt-BR.yml +21 -1
  69. data/config/locales/hyrax.zh.yml +21 -1
  70. data/hyrax.gemspec +7 -9
  71. data/lib/generators/hyrax/templates/catalog_controller.rb +1 -1
  72. data/lib/generators/hyrax/templates/config/locales/hyrax.pt-BR.yml +10 -10
  73. data/lib/generators/hyrax/work/templates/locale.pt-BR.yml.erb +1 -1
  74. data/lib/hyrax/configuration.rb +18 -0
  75. data/lib/hyrax/engine.rb +8 -0
  76. data/lib/hyrax/transactions/container.rb +6 -0
  77. data/lib/hyrax/transactions/destroy_work.rb +21 -0
  78. data/lib/hyrax/transactions/steps/destroy_work.rb +24 -0
  79. data/lib/hyrax/version.rb +1 -1
  80. data/lib/wings.rb +45 -0
  81. data/lib/wings/active_fedora_converter.rb +56 -0
  82. data/lib/wings/model_transformer.rb +158 -0
  83. data/lib/wings/resource_factory.rb +8 -0
  84. data/lib/wings/valkyrie/metadata_adapter.rb +29 -0
  85. data/lib/wings/valkyrie/persister.rb +50 -0
  86. data/lib/wings/valkyrie/query_service.rb +43 -0
  87. data/lib/wings/valkyrie/resource_factory.rb +45 -0
  88. data/lib/wings/valkyrizable.rb +24 -0
  89. data/lib/wings/value_mapper.rb +59 -0
  90. data/spec/abilities/collection_ability_spec.rb +5 -5
  91. data/spec/abilities/permission_template_ability_spec.rb +1 -1
  92. data/spec/actors/hyrax/actors/collections_membership_actor_spec.rb +6 -175
  93. data/spec/actors/hyrax/actors/create_with_remote_files_ordered_members_actor_spec.rb +30 -22
  94. data/spec/actors/hyrax/actors/interpret_visibility_actor_spec.rb +2 -0
  95. data/spec/controllers/catalog_controller_spec.rb +1 -1
  96. data/spec/controllers/hyrax/admin/collection_types_controller_spec.rb +1 -1
  97. data/spec/controllers/hyrax/batch_edits_controller_spec.rb +9 -9
  98. data/spec/controllers/hyrax/collections_controller_spec.rb +5 -5
  99. data/spec/controllers/hyrax/dashboard/collection_members_controller_spec.rb +16 -13
  100. data/spec/controllers/hyrax/dashboard/collections_controller_spec.rb +9 -9
  101. data/spec/controllers/hyrax/dashboard/nest_collections_controller_spec.rb +1 -1
  102. data/spec/controllers/hyrax/generic_works_controller_spec.rb +10 -1
  103. data/spec/controllers/hyrax/homepage_controller_spec.rb +3 -3
  104. data/spec/controllers/hyrax/my/shares_controller_spec.rb +1 -1
  105. data/spec/features/actor_stack_spec.rb +48 -0
  106. data/spec/features/catalog_search_spec.rb +2 -2
  107. data/spec/features/collection_multi_membership_spec.rb +2 -2
  108. data/spec/features/collection_spec.rb +7 -7
  109. data/spec/features/collection_type_spec.rb +2 -2
  110. data/spec/features/dashboard/collection_spec.rb +18 -18
  111. data/spec/features/delete_work_spec.rb +1 -1
  112. data/spec/features/search_spec.rb +2 -2
  113. data/spec/features/work_show_spec.rb +5 -2
  114. data/spec/forms/hyrax/forms/batch_upload_form_spec.rb +1 -0
  115. data/spec/forms/hyrax/forms/collection_form_spec.rb +5 -5
  116. data/spec/forms/hyrax/forms/permission_template_form_spec.rb +1 -1
  117. data/spec/forms/hyrax/forms/work_form_spec.rb +2 -0
  118. data/spec/helpers/blacklight_helper_spec.rb +3 -1
  119. data/spec/helpers/hyrax/collections_helper_spec.rb +42 -0
  120. data/spec/helpers/hyrax/dashboard_helper_behavior_spec.rb +4 -4
  121. data/spec/helpers/hyrax_helper_spec.rb +8 -4
  122. data/spec/hyrax/transactions/destroy_work_spec.rb +35 -0
  123. data/spec/hyrax/transactions/steps/destroy_work_spec.rb +33 -0
  124. data/spec/indexers/hyrax/collection_indexer_spec.rb +1 -1
  125. data/spec/jobs/characterize_job_spec.rb +1 -1
  126. data/spec/lib/hyrax/resource_sync/change_list_writer_spec.rb +35 -21
  127. data/spec/lib/hyrax/resource_sync/resource_list_writer_spec.rb +1 -1
  128. data/spec/models/collection_spec.rb +18 -18
  129. data/spec/models/concerns/hyrax/collection_nesting_spec.rb +2 -2
  130. data/spec/models/file_set_spec.rb +2 -2
  131. data/spec/models/hyrax/collection_type_spec.rb +2 -2
  132. data/spec/models/user_spec.rb +26 -1
  133. data/spec/presenters/hyrax/collection_presenter_spec.rb +11 -11
  134. data/spec/presenters/hyrax/work_show_presenter_spec.rb +11 -0
  135. data/spec/search_builders/hyrax/collection_member_search_builder_spec.rb +1 -1
  136. data/spec/search_builders/hyrax/collection_search_builder_spec.rb +1 -1
  137. data/spec/search_builders/hyrax/dashboard/nested_collections_search_builder_spec.rb +1 -1
  138. data/spec/search_builders/hyrax/work_relation_spec.rb +1 -1
  139. data/spec/services/hyrax/adapters/nesting_index_adapter_spec.rb +2 -2
  140. data/spec/services/hyrax/collections/collection_member_service_spec.rb +2 -2
  141. data/spec/services/hyrax/collections/migration_service_spec.rb +27 -27
  142. data/spec/services/hyrax/collections/nested_collection_persistence_service_spec.rb +1 -1
  143. data/spec/services/hyrax/collections/nested_collection_query_service_spec.rb +38 -38
  144. data/spec/services/hyrax/curation_concern_spec.rb +1 -1
  145. data/spec/services/hyrax/default_middleware_stack_spec.rb +1 -2
  146. data/spec/services/hyrax/statistics/depositors/summary_spec.rb +1 -1
  147. data/spec/services/hyrax/statistics/works/by_resource_type_spec.rb +11 -4
  148. data/spec/services/hyrax/visibility_intention_spec.rb +144 -0
  149. data/spec/services/hyrax/workflow/changes_required_notification_spec.rb +1 -1
  150. data/spec/spec_helper.rb +10 -8
  151. data/spec/support/selectors.rb +10 -1
  152. data/spec/test_app_templates/Gemfile.extra +2 -0
  153. data/spec/test_app_templates/lib/generators/test_app_generator.rb +6 -0
  154. data/spec/views/catalog/_index_list_default.html.erb_spec.rb +3 -2
  155. data/spec/views/catalog/_thumbnail_list_collection.html.erb_spec.rb +38 -5
  156. data/spec/views/hyrax/base/_attributes.html.erb_spec.rb +1 -1
  157. data/spec/views/hyrax/base/_show_actions.html.erb_spec.rb +9 -9
  158. data/spec/views/hyrax/base/show.html.erb_spec.rb +3 -2
  159. data/spec/views/hyrax/collections/_show_document_list_row.html.erb_spec.rb +3 -2
  160. data/spec/views/hyrax/dashboard/collections/_show_document_list_row.html.erb_spec.rb +3 -2
  161. data/spec/wings/active_fedora_converter_spec.rb +31 -0
  162. data/spec/wings/model_transformer_spec.rb +288 -0
  163. data/spec/wings/valkyrie/metadata_adapter_spec.rb +10 -0
  164. data/spec/wings/valkyrie/persister_spec.rb +71 -0
  165. data/spec/wings/valkyrie/query_service_spec.rb +81 -0
  166. data/spec/wings/valkyrie/resource_factory_spec.rb +32 -0
  167. data/spec/wings/value_mapper_spec.rb +60 -0
  168. data/spec/wings_spec.rb +8 -0
  169. data/template.rb +3 -1
  170. metadata +86 -36
@@ -161,7 +161,7 @@ class CatalogController < ApplicationController
161
161
  end
162
162
 
163
163
  config.add_search_field('description') do |field|
164
- field.label = "Abstract or Summary"
164
+ field.label = "Description"
165
165
  solr_name = solr_name("description", :stored_searchable)
166
166
  field.solr_local_parameters = {
167
167
  qf: solr_name,
@@ -5,7 +5,7 @@ pt-BR:
5
5
  fields:
6
6
  facet:
7
7
  based_near_label_sim: Localização
8
- creator_sim: O Criador
8
+ creator_sim: Criador
9
9
  file_format_sim: Formato
10
10
  generic_type_sim: Tipo
11
11
  keyword_sim: Palavra-chave
@@ -16,9 +16,9 @@ pt-BR:
16
16
  based_near_tesim: Localização
17
17
  contributor_tesim: Contribuinte
18
18
  creator_tesim: O Criador
19
- date_created_tesim: Data Criada
20
- date_modified_dtsi: Data modificada
21
- date_uploaded_dtsi: Data carregada
19
+ date_created_tesim: Data de Criação
20
+ date_modified_dtsi: Data de Modificação
21
+ date_uploaded_dtsi: Data de Carga
22
22
  description_tesim: Descrição
23
23
  file_format_tesim: Formato de arquivo
24
24
  identifier_tesim: Identificador
@@ -30,11 +30,11 @@ pt-BR:
30
30
  subject_tesim: Sujeito
31
31
  show:
32
32
  based_near_tesim: Localização
33
- contributor_tesim: Contribuinte
34
- creator_tesim: O Criador
35
- date_created_tesim: Data Criada
36
- date_modified_dtsi: Data modificada
37
- date_uploaded_dtsi: Data carregada
33
+ contributor_tesim: Colaborador
34
+ creator_tesim: Criador
35
+ date_created_tesim: Data de Criação
36
+ date_modified_dtsi: Data de Modificação
37
+ date_uploaded_dtsi: Data de Carga
38
38
  description_tesim: Descrição
39
39
  file_format_tesim: Formato de arquivo
40
40
  identifier_tesim: Identificador
@@ -50,7 +50,7 @@ pt-BR:
50
50
  directory:
51
51
  suffix: "@ Example.org"
52
52
  footer:
53
- copyright_html: "<strong>Copyright © 2017 Samvera Licenciado</strong> sob a Licença Apache, Versão 2.0"
53
+ copyright_html: "<strong>Copyright © 2018 Samvera </strong> Licenciado sob a Licença Apache, Versão 2.0"
54
54
  service_html: Um serviço de <a href="http://samvera.org/" class="navbar-link" target="_blank">Samvera</a> .
55
55
  institution_name: Instituição
56
56
  institution_name_full: O Nome da Instituição
@@ -4,5 +4,5 @@ pt-BR:
4
4
  <%= file_name %>: 'fa fa-file-text-o'
5
5
  select_type:
6
6
  <%= file_name %>:
7
- description: "<%= human_name %> trabalhos"
7
+ description: "<%= human_name %> obras"
8
8
  name: "<%= human_name.titleize %>"
@@ -222,6 +222,24 @@ module Hyrax
222
222
  registered_curation_concern_types.map(&:constantize)
223
223
  end
224
224
 
225
+ # The MetadataAdapter to use when persisting resources with Valkyrie
226
+ #
227
+ # @see lib/wings
228
+ # @see https://github.com/samvera-labs/valkyrie
229
+ def valkyrie_metadata_adapter
230
+ @valkyrie_metadata_adapter ||= :wings_adapter
231
+ end
232
+ attr_writer :valkyrie_metadata_adapter
233
+
234
+ # The StorageAdapter to use when persisting resources with Valkyrie
235
+ #
236
+ # @see lib/wings
237
+ # @see https://github.com/samvera-labs/valkyrie
238
+ def valkyrie_storage_adapter
239
+ @valkyrie_storage_adapter ||= :fedora
240
+ end
241
+ attr_writer :valkyrie_storage_adapter
242
+
225
243
  # A configuration point for changing the behavior of the license service.
226
244
  #
227
245
  # @!attribute [w] license_service_class
@@ -70,6 +70,14 @@ module Hyrax
70
70
  require 'dry/struct'
71
71
  require 'dry/equalizer'
72
72
  require 'dry/validation'
73
+ begin
74
+ require 'valkyrie'
75
+ rescue LoadError
76
+ message = "Hyrax::Engine.initializer did not load Valkyrie. We are in the process\n"
77
+ message += "\tof adding Valkyrie to Hyrax; For now you need do nothing. However,\n"
78
+ message += "\tstay tuned for release notes on what are the steps for incorporating Valkyrie."
79
+ Rails.logger.info(message)
80
+ end
73
81
  end
74
82
 
75
83
  initializer 'routing' do
@@ -19,7 +19,9 @@ module Hyrax
19
19
  # @see https://dry-rb.org/gems/dry-container/
20
20
  class Container
21
21
  require 'hyrax/transactions/create_work'
22
+ require 'hyrax/transactions/destroy_work'
22
23
  require 'hyrax/transactions/steps/apply_permission_template'
24
+ require 'hyrax/transactions/steps/destroy_work'
23
25
  require 'hyrax/transactions/steps/ensure_admin_set'
24
26
  require 'hyrax/transactions/steps/ensure_permission_template'
25
27
  require 'hyrax/transactions/steps/save_work'
@@ -34,6 +36,10 @@ module Hyrax
34
36
  Steps::ApplyPermissionTemplate.new
35
37
  end
36
38
 
39
+ ops.register 'destroy_work' do
40
+ Steps::DestroyWork.new
41
+ end
42
+
37
43
  ops.register 'ensure_admin_set' do
38
44
  Steps::EnsureAdminSet.new
39
45
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ module Hyrax
3
+ module Transactions
4
+ ##
5
+ # A transaction for destroying a Hyrax Work.
6
+ #
7
+ # @note This is an experimental replacement for the actor stack's `#destroy`
8
+ # stack. In time, we hope this will have feature parity with that stack,
9
+ # along with improved architecture, error handling, readability, and
10
+ # customizability. While this develops, please provide feedback.
11
+ #
12
+ # @since 3.0.0
13
+ #
14
+ # @see https://dry-rb.org/gems/dry-transaction/
15
+ class DestroyWork
16
+ include Dry::Transaction(container: Hyrax::Transactions::Container)
17
+
18
+ step :destroy_work, with: 'work.destroy_work'
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ module Hyrax
3
+ module Transactions
4
+ module Steps
5
+ ##
6
+ # A `dry-transcation` step that destroys a Work.
7
+ #
8
+ # @since 3.0.0
9
+ class DestroyWork
10
+ include Dry::Transaction::Operation
11
+
12
+ ##
13
+ # @param [Hyrax::WorkBehavior] work
14
+ #
15
+ # @return [Dry::Monads::Result]
16
+ def call(work)
17
+ work.destroy! && Success(work)
18
+ rescue => err
19
+ Failure(err)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,3 +1,3 @@
1
1
  module Hyrax
2
- VERSION = '3.0.0-beta1'.freeze
2
+ VERSION = '3.0.0-beta2'.freeze
3
3
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # Wings is a toolkit integrating Valkyrie into Hyrax as a bridge away from the
5
+ # hard dependency on ActiveFedora.
6
+ #
7
+ # Requiring this module with `require 'wings'` injects a variety of behavior
8
+ # supporting a gradual transition from existing `ActiveFedora` models and
9
+ # persistence middleware to Valkyrie.
10
+ #
11
+ # `Wings` is primarily an isolating namespace for code intended to be removed
12
+ # after a full transition to `Valkyrie` as the persistence middleware for Hyrax.
13
+ # Applications may find it useful to depend directly on this code to facilitate
14
+ # a smooth code migration, much in the way it is being used in this engine.
15
+ # However, these dependencies should be considered temprorary: this code will
16
+ # be deprecated for removal in a future release.
17
+ #
18
+ # @see https://wiki.duraspace.org/display/samvera/Hyrax-Valkyrie+Development+Working+Group
19
+ # for further context regarding the approach
20
+ module Wings; end
21
+
22
+ require 'valkyrie'
23
+ require 'wings/model_transformer'
24
+ require 'wings/resource_factory'
25
+ require 'wings/valkyrizable'
26
+ require 'wings/valkyrie/metadata_adapter'
27
+ require 'wings/valkyrie/resource_factory'
28
+ require 'wings/valkyrie/persister'
29
+ require 'wings/valkyrie/query_service'
30
+
31
+ ActiveFedora::Base.include Wings::Valkyrizable
32
+
33
+ Valkyrie.config.resource_class_resolver = lambda do |_klass_name|
34
+ Wings::ModelTransformer.convert_class_name_to_valkyrie_resource_class(internal_resource)
35
+ end
36
+
37
+ Valkyrie::MetadataAdapter.register(
38
+ Wings::Valkyrie::MetadataAdapter.new, :wings_adapter
39
+ )
40
+
41
+ Valkyrie::StorageAdapter.register(
42
+ Valkyrie::Storage::Fedora
43
+ .new(connection: Ldp::Client.new(ActiveFedora.fedora.host)),
44
+ :fedora
45
+ )
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wings
4
+ ##
5
+ # Converts `ValkyrieResource` objects to legacy `ActiveFedora::Base` objects.
6
+ #
7
+ # @example
8
+ # work = GenericWork.new(title: ['Comet in Moominland'])
9
+ # resource = GenericWork.valkyrie_resource
10
+ #
11
+ # ActiveFedoraConverter.new(resource: resource).convert == work # => true
12
+ #
13
+ # @note the `Valkyrie::Resource` object passed to this class **must** have an
14
+ # `#internal_resource` mapping it to an `ActiveFedora::Base` class.
15
+ class ActiveFedoraConverter
16
+ ##
17
+ # @!attribute [rw] resource
18
+ # @return [Valkyrie::Resource]
19
+ attr_accessor :resource
20
+
21
+ ##
22
+ # @param [Valkyrie::Resource]
23
+ def initialize(resource:)
24
+ @resource = resource
25
+ end
26
+
27
+ ##
28
+ # @return [Hash<Symbol, Object>]
29
+ def attributes
30
+ attrs = resource.attributes
31
+
32
+ # avoid reflections for now; `*_ids` can't be passed as attributes.
33
+ # handling for reflections needs to happen in future work
34
+ attrs = attrs.reject { |k, _| k.to_s.end_with? '_ids' }
35
+
36
+ attrs.delete(:internal_resource)
37
+ attrs.delete(:new_record)
38
+ attrs.delete(:id)
39
+ attrs.delete(:alternate_ids)
40
+
41
+ attrs.compact
42
+ end
43
+
44
+ ##
45
+ # @return [ActiveFedora::Base]
46
+ def convert
47
+ resource.internal_resource.new(attributes).tap { |obj| obj.id = id unless id.empty? }
48
+ end
49
+
50
+ ##
51
+ # @return [String]
52
+ def id
53
+ resource.alternate_ids.first.to_s
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'wings/value_mapper'
4
+
5
+ module Wings
6
+ #
7
+ # This class is responsible for coordinating the transformation of a PCDM
8
+ # Model (be it the class or an instance of the class) to a [Valkyrie::Resource](https://github.com/samvera-labs/valkyrie/blob/master/lib/valkyrie/resource.rb).
9
+ # for the given PCDM model.
10
+ #
11
+ # @example getting a valkyrie resource
12
+ # work = GenericWork.new(id: 'an_identifier')
13
+ # resource = Wings::ModelTransformer.for(pcdm_object: work)
14
+ #
15
+ # resource.alternate_ids # => [#<Valkyrie::ID:0x... id: 'an_identifier'>]
16
+ #
17
+ class ModelTransformer
18
+ ##
19
+ # Caches dynamically generated `Valkyrie::Resource` subclasses mapped from
20
+ # legacy `ActiveFedora` model classes.
21
+ #
22
+ # @example
23
+ # cache = ResourceClassCache.new
24
+ #
25
+ # klass = cache.fetch(GenericWork) do
26
+ # # logic mapping GenericWork to a Valkyrie::Resource subclass
27
+ # end
28
+ #
29
+ class ResourceClassCache
30
+ ##
31
+ # @!attribute [r] cache
32
+ # @return [Hash<Class, Class>]
33
+ attr_reader :cache
34
+
35
+ def initialize
36
+ @cache = {}
37
+ end
38
+
39
+ ##
40
+ # @param key [Class] the ActiveFedora class to map
41
+ #
42
+ # @return [Class]
43
+ def fetch(key)
44
+ @cache.fetch(key) do
45
+ @cache[key] = yield
46
+ end
47
+ end
48
+ end
49
+
50
+ # we really want a class var here. maybe we could use a singleton instead?
51
+ # rubocop:disable Style/ClassVars
52
+ @@resource_class_cache = ResourceClassCache.new
53
+
54
+ ##
55
+ # @!attribute [rw] pcdm_object
56
+ # @return [ActiveFedora::Base]
57
+ attr_accessor :pcdm_object
58
+
59
+ ##
60
+ # @note The method signature is to conform to Valkyrie's method signature
61
+ # for ::Valkyrie.config.resource_class_resolver
62
+ #
63
+ # @param class_name [String] a string representation of an `ActiveFedora`
64
+ # model
65
+ #
66
+ # @return [Class] a dynamically generated `Valkyrie::Resource` subclass
67
+ # mirroring the provided class name
68
+ #
69
+ def self.convert_class_name_to_valkyrie_resource_class(class_name)
70
+ klass = class_name.constantize
71
+ to_valkyrie_resource_class(klass: klass)
72
+ end
73
+
74
+ ##
75
+ # @param klass [String] an `ActiveFedora` model
76
+ #
77
+ # @return [Class] a dyamically generated `Valkyrie::Resource` subclass
78
+ # mirroring the provided `ActiveFedora` model
79
+ #
80
+ # rubocop:disable Metrics/MethodLength because metaprogramming a class
81
+ # results in long methods
82
+ def self.to_valkyrie_resource_class(klass:)
83
+ Class.new(ActiveFedoraResource) do
84
+ # Based on Valkyrie implementation, we call Class.to_s to define
85
+ # the internal resource.
86
+ @internal_resource = klass
87
+
88
+ class << self
89
+ attr_reader :internal_resource
90
+ end
91
+
92
+ def self.to_s
93
+ internal_resource.to_s
94
+ end
95
+
96
+ klass.properties.each_key do |property_name|
97
+ attribute property_name.to_sym, ::Valkyrie::Types::String
98
+ end
99
+ relationship_keys = klass.reflections.keys.reject { |k| k.to_s.include?('id') }.map { |k| k.to_s.singularize + '_ids' }
100
+ relationship_keys.each do |linked_property_name|
101
+ attribute linked_property_name.to_sym, ::Valkyrie::Types::Set.of(::Valkyrie::Types::ID)
102
+ end
103
+
104
+ # Defined after properties in case we have an `internal_resource` property.
105
+ # This may not be ideal, but based on my understanding of the `internal_resource`
106
+ # usage in Valkyrie, I'd rather keep synchronized the instance_method and class_method value for
107
+ # `internal_resource`
108
+ def internal_resource
109
+ self.class.internal_resource
110
+ end
111
+ end
112
+ end
113
+ # rubocop:enable Metrics/MethodLength
114
+
115
+ ##
116
+ # @param pcdm_object [ActiveFedora::Base]
117
+ def initialize(pcdm_object:)
118
+ self.pcdm_object = pcdm_object
119
+ end
120
+
121
+ ##
122
+ # @param pcdm_object [ActiveFedora::Base]
123
+ #
124
+ # @return [::Valkyrie::Resource] a resource mirroiring `pcdm_object`
125
+ def self.for(pcdm_object)
126
+ new(pcdm_object: pcdm_object).build
127
+ end
128
+
129
+ ##
130
+ # Builds a `Valkyrie::Resource` equivalent to the `pcdm_object`
131
+ #
132
+ # @return [::Valkyrie::Resource] a resource mirroiring `pcdm_object`
133
+ def build
134
+ klass = @@resource_class_cache.fetch(pcdm_object) do
135
+ self.class.to_valkyrie_resource_class(klass: pcdm_object.class)
136
+ end
137
+ klass.new(alternate_ids: [::Valkyrie::ID.new(pcdm_object.id)], **attributes)
138
+ end
139
+
140
+ class ActiveFedoraResource < ::Valkyrie::Resource
141
+ attribute :alternate_ids, ::Valkyrie::Types::Array
142
+ end
143
+
144
+ private
145
+
146
+ def attributes
147
+ relationship_keys = pcdm_object.reflections.keys.reject { |k| k.to_s.include?('id') }.map { |k| k.to_s.singularize + '_ids' }
148
+
149
+ attrs_with_relationships = pcdm_object.attributes.keys + relationship_keys
150
+
151
+ attrs_with_relationships.each_with_object({}) do |attr_name, mem|
152
+ next unless pcdm_object.respond_to? attr_name
153
+ mem[attr_name.to_sym] = ValueMapper.for(pcdm_object.public_send(attr_name)).result
154
+ end
155
+ end
156
+ end
157
+ # rubocop:enable Style/ClassVars
158
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wings
4
+ # Preserving the old class for short-standing compliance
5
+ # with other Wings development. This can go away as part of the
6
+ # end of the Penn State 2019 winter developer sprint.
7
+ class ResourceFactory < ModelTransformer; end
8
+ end