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

Sign up to get free protection for your applications and to get access to all the features.
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