hyrax 3.3.0 → 3.4.2

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 (255) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +26 -17
  3. data/.dassie/.env +2 -1
  4. data/.dassie/Gemfile +1 -1
  5. data/.dassie/app/forms/collection_resource_form.rb +8 -0
  6. data/.dassie/app/indexers/collection_resource_indexer.rb +8 -0
  7. data/.dassie/app/models/collection_resource.rb +35 -0
  8. data/.dassie/config/initializers/file_services.rb +4 -0
  9. data/.dassie/config/initializers/hyrax.rb +12 -1
  10. data/.dassie/config/metadata/collection_resource.yaml +23 -0
  11. data/.dassie/db/seeds.rb +74 -17
  12. data/.dassie/spec/forms/collection_resource_form_spec.rb +13 -0
  13. data/.dassie/spec/indexers/collection_resource_indexer_spec.rb +14 -0
  14. data/.dassie/spec/models/collection_resource_spec.rb +13 -0
  15. data/.github/release.yml +26 -0
  16. data/.gitignore +3 -0
  17. data/.regen +1 -1
  18. data/.rubocop.yml +1 -1
  19. data/.rubocop_fixme.yml +22 -3
  20. data/CONTAINERS.md +18 -13
  21. data/Dockerfile +4 -3
  22. data/app/actors/hyrax/actors/file_actor.rb +6 -4
  23. data/app/actors/hyrax/actors/transfer_request_actor.rb +3 -7
  24. data/app/assets/javascripts/hyrax/analytics_events.js +8 -2
  25. data/app/assets/javascripts/hyrax/autocomplete/linked_data.es6 +1 -3
  26. data/app/assets/javascripts/hyrax/collections_v2.es6 +13 -0
  27. data/app/controllers/concerns/hyrax/collections_controller_behavior.rb +1 -3
  28. data/app/controllers/concerns/hyrax/controller.rb +21 -0
  29. data/app/controllers/concerns/hyrax/works_controller_behavior.rb +83 -59
  30. data/app/controllers/hyrax/admin/admin_sets_controller.rb +105 -19
  31. data/app/controllers/hyrax/admin/permission_template_accesses_controller.rb +12 -19
  32. data/app/controllers/hyrax/batch_edits_controller.rb +12 -3
  33. data/app/controllers/hyrax/batch_uploads_controller.rb +4 -0
  34. data/app/controllers/hyrax/citations_controller.rb +1 -1
  35. data/app/controllers/hyrax/dashboard/collections_controller.rb +176 -83
  36. data/app/controllers/hyrax/single_use_links_viewer_controller.rb +1 -1
  37. data/app/forms/hyrax/forms/administrative_set_form.rb +19 -1
  38. data/app/forms/hyrax/forms/batch_edit_form.rb +1 -1
  39. data/app/forms/hyrax/forms/collection_form.rb +1 -1
  40. data/app/forms/hyrax/forms/dashboard/nest_collection_form.rb +21 -6
  41. data/app/forms/hyrax/forms/pcdm_collection_form.rb +30 -2
  42. data/app/forms/hyrax/forms/permission_template_form.rb +17 -9
  43. data/app/forms/hyrax/forms/resource_form.rb +23 -5
  44. data/app/forms/hyrax/forms/widgets/admin_set_visibility.rb +1 -1
  45. data/app/helpers/hyrax/collections_helper.rb +14 -0
  46. data/app/helpers/hyrax/membership_helper.rb +1 -1
  47. data/app/helpers/hyrax/trophy_helper.rb +1 -1
  48. data/app/helpers/hyrax/url_helper.rb +1 -1
  49. data/app/indexers/hyrax/administrative_set_indexer.rb +8 -2
  50. data/app/indexers/hyrax/deep_indexing_service.rb +1 -1
  51. data/app/indexers/hyrax/file_set_indexer.rb +1 -0
  52. data/app/indexers/hyrax/pcdm_collection_indexer.rb +3 -2
  53. data/app/indexers/hyrax/thumbnail_indexer.rb +31 -0
  54. data/app/indexers/hyrax/valkyrie_file_set_indexer.rb +6 -6
  55. data/app/indexers/hyrax/valkyrie_indexer.rb +4 -2
  56. data/app/indexers/hyrax/valkyrie_work_indexer.rb +13 -0
  57. data/app/inputs/controlled_vocabulary_input.rb +2 -0
  58. data/app/jobs/change_depositor_event_job.rb +47 -0
  59. data/app/jobs/characterize_job.rb +43 -3
  60. data/app/jobs/concerns/hyrax/members_permission_job_behavior.rb +1 -1
  61. data/app/jobs/content_depositor_change_event_job.rb +2 -1
  62. data/app/jobs/hyrax/propagate_change_depositor_job.rb +32 -0
  63. data/app/jobs/import_url_job.rb +4 -6
  64. data/app/jobs/inherit_permissions_job.rb +1 -1
  65. data/app/jobs/valkyrie_create_derivatives_job.rb +25 -0
  66. data/app/jobs/valkyrie_ingest_job.rb +41 -35
  67. data/app/models/admin_set.rb +10 -2
  68. data/app/models/collection_branding_info.rb +8 -6
  69. data/app/models/concerns/hyrax/collection_behavior.rb +3 -3
  70. data/app/models/concerns/hyrax/file_set/characterization.rb +7 -1
  71. data/app/models/concerns/hyrax/solr_document/metadata.rb +1 -0
  72. data/app/models/concerns/hyrax/solr_document_behavior.rb +9 -3
  73. data/app/models/concerns/hyrax/user.rb +11 -0
  74. data/app/models/concerns/hyrax/work_behavior.rb +1 -1
  75. data/app/models/featured_work_list.rb +0 -1
  76. data/app/models/hyrax/administrative_set.rb +36 -1
  77. data/app/models/hyrax/collection_type.rb +2 -2
  78. data/app/models/hyrax/file_metadata.rb +37 -3
  79. data/app/models/hyrax/file_set.rb +43 -4
  80. data/app/models/hyrax/group.rb +19 -0
  81. data/app/models/hyrax/pcdm_collection.rb +56 -1
  82. data/app/models/hyrax/permission_template.rb +11 -5
  83. data/app/models/hyrax/work.rb +91 -0
  84. data/app/models/job_io_wrapper.rb +1 -1
  85. data/app/models/proxy_deposit_request.rb +1 -1
  86. data/app/presenters/hyrax/admin_set_presenter.rb +2 -2
  87. data/app/presenters/hyrax/member_presenter_factory.rb +2 -4
  88. data/app/presenters/hyrax/pcdm_member_presenter_factory.rb +2 -2
  89. data/app/presenters/hyrax/work_show_presenter.rb +10 -6
  90. data/app/search_builders/hyrax/dashboard/collections_search_builder.rb +2 -2
  91. data/app/search_builders/hyrax/dashboard/managed_search_filters.rb +44 -4
  92. data/app/search_builders/hyrax/dashboard/nested_collections_search_builder.rb +2 -2
  93. data/app/search_builders/hyrax/my/collections_search_builder.rb +11 -4
  94. data/app/services/hyrax/access_control_list.rb +20 -6
  95. data/app/services/hyrax/adapters/nesting_index_adapter.rb +3 -3
  96. data/app/services/hyrax/admin_set_create_service.rb +21 -37
  97. data/app/services/hyrax/change_content_depositor_service.rb +2 -2
  98. data/app/services/hyrax/change_depositor_service.rb +70 -0
  99. data/app/services/hyrax/characterization/valkyrie_characterization_service.rb +4 -6
  100. data/app/services/hyrax/collections/collection_member_service.rb +3 -5
  101. data/app/services/hyrax/collections/nested_collection_query_service.rb +24 -12
  102. data/app/services/hyrax/custom_queries/navigators/child_file_sets_navigator.rb +45 -0
  103. data/app/services/hyrax/custom_queries/navigators/child_filesets_navigator.rb +7 -2
  104. data/app/services/hyrax/custom_queries/navigators/parent_work_navigator.rb +54 -0
  105. data/app/services/hyrax/default_middleware_stack.rb +3 -0
  106. data/app/services/hyrax/file_set_derivatives_service.rb +21 -2
  107. data/app/services/hyrax/file_set_type_service.rb +2 -5
  108. data/app/services/hyrax/listeners/file_metadata_listener.rb +31 -1
  109. data/app/services/hyrax/listeners/member_cleanup_listener.rb +27 -11
  110. data/app/services/hyrax/listeners/metadata_index_listener.rb +39 -0
  111. data/app/services/hyrax/listeners/proxy_deposit_listener.rb +14 -8
  112. data/app/services/hyrax/location_service.rb +33 -0
  113. data/app/services/hyrax/multiple_membership_checker.rb +46 -1
  114. data/app/services/hyrax/resource_visibility_propagator.rb +1 -1
  115. data/app/services/hyrax/simple_schema_loader.rb +5 -1
  116. data/app/services/hyrax/solr_query_service.rb +12 -7
  117. data/app/services/hyrax/thumbnail_path_service.rb +1 -1
  118. data/app/services/hyrax/valkyrie_persist_derivatives.rb +50 -0
  119. data/app/services/hyrax/valkyrie_upload.rb +94 -0
  120. data/app/services/hyrax/work_uploads_handler.rb +0 -10
  121. data/app/services/hyrax/workflow/workflow_importer.rb +7 -9
  122. data/app/services/hyrax/workflow/workflow_schema.rb +3 -5
  123. data/app/strategies/hyrax/strategies/yaml_strategy.rb +4 -6
  124. data/app/uploaders/hyrax/uploaded_file_uploader.rb +4 -4
  125. data/app/utils/hyrax/data_destroyers/collection_branding_destroyer.rb +29 -0
  126. data/app/utils/hyrax/data_destroyers/collection_types_destroyer.rb +26 -0
  127. data/app/utils/hyrax/data_destroyers/default_admin_set_id_cache_destroyer.rb +26 -0
  128. data/app/utils/hyrax/data_destroyers/featured_works_destroyer.rb +27 -0
  129. data/app/utils/hyrax/data_destroyers/permission_templates_destroyer.rb +30 -0
  130. data/app/utils/hyrax/data_destroyers/repository_metadata_destroyer.rb +42 -0
  131. data/app/utils/hyrax/data_destroyers/stats_destroyer.rb +33 -0
  132. data/app/utils/hyrax/data_maintenance.rb +51 -0
  133. data/app/utils/hyrax/required_data_seeder.rb +21 -0
  134. data/app/utils/hyrax/required_data_seeders/collection_seeder.rb +26 -0
  135. data/app/utils/hyrax/required_data_seeders/collection_type_seeder.rb +36 -0
  136. data/app/utils/hyrax/test_data_seeder.rb +24 -0
  137. data/app/utils/hyrax/test_data_seeders/collection_seeder.rb +91 -0
  138. data/app/utils/hyrax/test_data_seeders/collection_type_seeder.rb +72 -0
  139. data/app/utils/hyrax/test_data_seeders/user_seeder.rb +52 -0
  140. data/app/validators/hyrax/collection_membership_validator.rb +39 -0
  141. data/app/views/catalog/_index_header_list_default.html.erb +8 -1
  142. data/app/views/catalog/_thumbnail_list_default.html.erb +8 -3
  143. data/app/views/collections/edit_fields/_based_near.html.erb +7 -7
  144. data/app/views/hyrax/admin/admin_sets/_form_participant_table.html.erb +2 -2
  145. data/app/views/hyrax/admin/admin_sets/_form_participants.html.erb +2 -2
  146. data/app/views/hyrax/admin/admin_sets/_form_visibility.html.erb +2 -2
  147. data/app/views/hyrax/admin/admin_sets/_form_workflow.erb +1 -1
  148. data/app/views/hyrax/admin/collection_types/index.html.erb +1 -1
  149. data/app/views/hyrax/base/_form.html.erb +1 -1
  150. data/app/views/hyrax/base/_form_child_work_relationships.html.erb +1 -1
  151. data/app/views/hyrax/dashboard/collections/_default_group.html.erb +2 -2
  152. data/app/views/hyrax/dashboard/collections/_form.html.erb +24 -17
  153. data/app/views/hyrax/dashboard/collections/_form_branding.html.erb +1 -0
  154. data/app/views/hyrax/dashboard/collections/_form_discovery.html.erb +6 -3
  155. data/app/views/hyrax/dashboard/collections/_form_share.html.erb +2 -2
  156. data/app/views/hyrax/dashboard/collections/_form_share_table.html.erb +3 -3
  157. data/app/views/hyrax/dashboard/collections/_list_collections.html.erb +2 -2
  158. data/app/views/hyrax/dashboard/sidebar/_activity.html.erb +1 -1
  159. data/app/views/hyrax/dashboard/works/_default_group.html.erb +1 -1
  160. data/app/views/hyrax/dashboard/works/_list_works.html.erb +1 -1
  161. data/app/views/hyrax/file_sets/_actions.html.erb +2 -2
  162. data/app/views/hyrax/my/_facet_pagination.html.erb +12 -9
  163. data/app/views/hyrax/my/_work_action_menu.html.erb +8 -9
  164. data/app/views/hyrax/my/collections/_default_group.html.erb +2 -2
  165. data/app/views/hyrax/my/collections/_list_collections.html.erb +2 -2
  166. data/app/views/hyrax/my/collections/index.html.erb +3 -2
  167. data/app/views/hyrax/my/works/_default_group.html.erb +1 -1
  168. data/app/views/hyrax/my/works/_list_works.html.erb +1 -2
  169. data/app/views/hyrax/my/works/_tabs.html.erb +6 -1
  170. data/app/views/hyrax/my/works/index.html.erb +4 -2
  171. data/chart/hyrax/Chart.yaml +11 -7
  172. data/chart/hyrax/README.md +22 -1
  173. data/chart/hyrax/templates/_helpers.tpl +4 -0
  174. data/chart/hyrax/templates/cron-embargo.yaml +5 -0
  175. data/chart/hyrax/templates/cron-lease.yaml +5 -0
  176. data/chart/hyrax/templates/deployment-worker.yaml +11 -0
  177. data/chart/hyrax/templates/ingress.yaml +7 -6
  178. data/chart/hyrax/values.yaml +152 -0
  179. data/config/features.rb +48 -50
  180. data/config/initializers/listeners.rb +0 -1
  181. data/config/initializers/{valkryrie_storage.rb → storage_adapter_initializer.rb} +5 -0
  182. data/config/locales/hyrax.de.yml +18 -17
  183. data/config/locales/hyrax.en.yml +30 -28
  184. data/config/locales/hyrax.es.yml +10 -9
  185. data/config/locales/hyrax.fr.yml +2 -1
  186. data/config/locales/hyrax.it.yml +3 -2
  187. data/config/locales/hyrax.pt-BR.yml +2 -1
  188. data/config/locales/hyrax.zh.yml +2 -1
  189. data/config/metadata/basic_metadata.yaml +2 -0
  190. data/config/metadata/core_metadata.yaml +1 -1
  191. data/docker-compose.yml +47 -42
  192. data/documentation/developing-your-hyrax-based-app.md +1 -1
  193. data/documentation/legacyREADME.md +1 -1
  194. data/hyrax.gemspec +5 -3
  195. data/lib/generators/hyrax/collection_resource/USAGE +20 -0
  196. data/lib/generators/hyrax/collection_resource/collection_resource_generator.rb +133 -0
  197. data/lib/generators/hyrax/collection_resource/templates/collection.rb.erb +34 -0
  198. data/lib/generators/hyrax/collection_resource/templates/collection_form.rb.erb +7 -0
  199. data/lib/generators/hyrax/collection_resource/templates/collection_form_spec.rb.erb +13 -0
  200. data/lib/generators/hyrax/collection_resource/templates/collection_indexer.rb.erb +7 -0
  201. data/lib/generators/hyrax/collection_resource/templates/collection_indexer_spec.rb.erb +13 -0
  202. data/lib/generators/hyrax/collection_resource/templates/collection_metadata.yaml +22 -0
  203. data/lib/generators/hyrax/collection_resource/templates/collection_spec.rb.erb +12 -0
  204. data/lib/generators/hyrax/install_generator.rb +9 -0
  205. data/lib/hyrax/administrative_set_name.rb +18 -0
  206. data/lib/hyrax/collection_name.rb +2 -0
  207. data/lib/hyrax/configuration.rb +22 -0
  208. data/lib/hyrax/controlled_vocabularies/location.rb +9 -2
  209. data/lib/hyrax/controlled_vocabularies/resource_label_caching.rb +42 -0
  210. data/lib/hyrax/controlled_vocabularies.rb +1 -0
  211. data/lib/hyrax/publisher.rb +49 -0
  212. data/lib/hyrax/schema.rb +16 -13
  213. data/lib/hyrax/specs/capybara.rb +1 -1
  214. data/lib/hyrax/specs/shared_specs/hydra_works.rb +11 -5
  215. data/lib/hyrax/specs/shared_specs/indexers.rb +117 -3
  216. data/lib/hyrax/transactions/admin_set_create.rb +2 -1
  217. data/lib/hyrax/transactions/admin_set_destroy.rb +22 -0
  218. data/lib/hyrax/transactions/admin_set_update.rb +21 -0
  219. data/lib/hyrax/transactions/collection_destroy.rb +22 -0
  220. data/lib/hyrax/transactions/collection_update.rb +5 -2
  221. data/lib/hyrax/transactions/container.rb +97 -23
  222. data/lib/hyrax/transactions/create_work.rb +3 -0
  223. data/lib/hyrax/transactions/destroy_work.rb +3 -0
  224. data/lib/hyrax/transactions/steps/apply_collection_permission_template.rb +2 -0
  225. data/lib/hyrax/transactions/steps/apply_permission_template.rb +2 -0
  226. data/lib/hyrax/transactions/steps/apply_visibility.rb +2 -0
  227. data/lib/hyrax/transactions/steps/change_depositor.rb +46 -0
  228. data/lib/hyrax/transactions/steps/check_for_empty_admin_set.rb +36 -0
  229. data/lib/hyrax/transactions/steps/delete_access_control.rb +32 -0
  230. data/lib/hyrax/transactions/steps/delete_resource.rb +19 -3
  231. data/lib/hyrax/transactions/steps/destroy_work.rb +3 -1
  232. data/lib/hyrax/transactions/steps/ensure_permission_template.rb +2 -0
  233. data/lib/hyrax/transactions/steps/save.rb +24 -6
  234. data/lib/hyrax/transactions/steps/save_access_control.rb +2 -2
  235. data/lib/hyrax/transactions/steps/save_collection_banner.rb +59 -0
  236. data/lib/hyrax/transactions/steps/save_collection_logo.rb +109 -0
  237. data/lib/hyrax/transactions/steps/save_work.rb +3 -0
  238. data/lib/hyrax/transactions/steps/set_user_as_creator.rb +41 -0
  239. data/lib/hyrax/transactions/steps/update_work_members.rb +51 -0
  240. data/lib/hyrax/transactions/update_work.rb +4 -3
  241. data/lib/hyrax/transactions/work_create.rb +1 -1
  242. data/lib/hyrax/transactions/work_destroy.rb +2 -1
  243. data/lib/hyrax/transactions/work_update.rb +19 -0
  244. data/lib/hyrax/version.rb +1 -1
  245. data/lib/wings/active_fedora_converter/file_metadata_node.rb +48 -0
  246. data/lib/wings/active_fedora_converter/instance_builder.rb +68 -0
  247. data/lib/wings/active_fedora_converter.rb +3 -3
  248. data/lib/wings/attribute_transformer.rb +5 -1
  249. data/lib/wings/services/custom_queries/find_file_metadata.rb +19 -8
  250. data/lib/wings/setup.rb +3 -1
  251. data/lib/wings/valkyrie/persister.rb +2 -0
  252. data/lib/wings/valkyrie/query_service.rb +6 -7
  253. data/lib/wings/valkyrie/storage.rb +7 -1
  254. data/template.rb +1 -1
  255. metadata +99 -12
@@ -14,8 +14,9 @@ module Hyrax
14
14
 
15
15
  ##
16
16
  # @params [#save] persister
17
- def initialize(persister: Hyrax.persister)
17
+ def initialize(persister: Hyrax.persister, publisher: Hyrax.publisher)
18
18
  @persister = persister
19
+ @publisher = publisher
19
20
  end
20
21
 
21
22
  ##
@@ -27,11 +28,26 @@ module Hyrax
27
28
  return Failure(:resource_not_persisted) unless resource.persisted?
28
29
 
29
30
  @persister.delete(resource: resource)
30
- Hyrax.publisher
31
- .publish('object.deleted', object: resource, id: resource.id.id, user: user)
31
+ publish_changes(resource: resource, user: user)
32
32
 
33
33
  Success(resource)
34
34
  end
35
+
36
+ private
37
+
38
+ def publish_changes(resource:, user:)
39
+ if resource.collection?
40
+ @publisher.publish('collection.deleted',
41
+ collection: resource,
42
+ id: resource.id.id,
43
+ user: user)
44
+ else
45
+ @publisher.publish('object.deleted',
46
+ object: resource,
47
+ id: resource.id.id,
48
+ user: user)
49
+ end
50
+ end
35
51
  end
36
52
  end
37
53
  end
@@ -6,7 +6,9 @@ module Hyrax
6
6
  # A `dry-transcation` step that destroys a Work.
7
7
  #
8
8
  # @since 3.0.0
9
- # @deprecated
9
+ # @deprecated This is part of the legacy AF set of transaction steps for works.
10
+ # Transactions are not being used with AF works. This will be removed in 4.0.
11
+ # @see Hyrax::Transactions::Steps::DeleteResource
10
12
  class DestroyWork
11
13
  include Dry::Transaction::Operation
12
14
 
@@ -7,6 +7,8 @@ module Hyrax
7
7
  # template.
8
8
  #
9
9
  # @since 2.4.0
10
+ # @deprecated This is part of the legacy AF set of transaction steps for works.
11
+ # Transactions are not being used with AF works. This will be removed in 4.0.
10
12
  class EnsurePermissionTemplate
11
13
  include Dry::Transaction::Operation
12
14
 
@@ -17,8 +17,9 @@ module Hyrax
17
17
 
18
18
  ##
19
19
  # @params [#save] persister
20
- def initialize(persister: Hyrax.persister)
20
+ def initialize(persister: Hyrax.persister, publisher: Hyrax.publisher)
21
21
  @persister = persister
22
+ @publisher = publisher
22
23
  end
23
24
 
24
25
  ##
@@ -30,6 +31,7 @@ module Hyrax
30
31
  # `Failure([#to_s, change_set.resource])`, otherwise.
31
32
  def call(change_set, user: nil)
32
33
  begin
34
+ new_collections = changed_collection_membership(change_set)
33
35
  unsaved = change_set.sync
34
36
  saved = @persister.save(resource: unsaved)
35
37
  rescue StandardError => err
@@ -43,18 +45,34 @@ module Hyrax
43
45
 
44
46
  user ||= ::User.find_by_user_key(saved.depositor)
45
47
 
46
- publish_changes(resource: saved, user: user, new: unsaved.new_record)
48
+ publish_changes(resource: saved, user: user, new: unsaved.new_record, new_collections: new_collections)
47
49
  Success(saved)
48
50
  end
49
51
 
50
52
  private
51
53
 
52
- def publish_changes(resource:, user:, new: false)
54
+ ##
55
+ # @param [Hyrax::ChangeSet] change_set
56
+ #
57
+ # @return [Array<Valkyrie::ID>]
58
+ def changed_collection_membership(change_set)
59
+ return [] unless change_set.changed?(:member_of_collection_ids)
60
+
61
+ change_set.member_of_collection_ids - change_set.model.member_of_collection_ids
62
+ end
63
+
64
+ def publish_changes(resource:, user:, new: false, new_collections: [])
53
65
  if resource.collection?
54
- Hyrax.publisher.publish('collection.metadata.updated', collection: resource, user: user)
66
+ @publisher.publish('collection.metadata.updated', collection: resource, user: user)
55
67
  else
56
- Hyrax.publisher.publish('object.deposited', object: resource, user: user) if new
57
- Hyrax.publisher.publish('object.metadata.updated', object: resource, user: user)
68
+ @publisher.publish('object.deposited', object: resource, user: user) if new
69
+ @publisher.publish('object.metadata.updated', object: resource, user: user)
70
+ end
71
+
72
+ new_collections.each do |collection_id|
73
+ @publisher.publish('collection.membership.updated',
74
+ collection_id: collection_id,
75
+ user: user)
58
76
  end
59
77
  end
60
78
  end
@@ -18,8 +18,8 @@ module Hyrax
18
18
  # @return [Dry::Monads::Result]
19
19
  def call(obj)
20
20
  return Success(obj) unless obj.respond_to?(:permission_manager)
21
- obj.permission_manager&.acl&.save ||
22
- (return Failure[:failed_to_save_acl, acl])
21
+ acl = obj.permission_manager&.acl
22
+ acl&.save || (return Failure[:failed_to_save_acl, acl])
23
23
 
24
24
  Success(obj)
25
25
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+ module Hyrax
3
+ module Transactions
4
+ module Steps
5
+ ##
6
+ # Adds banner info via `ChangeSet`.
7
+ #
8
+ # During the update collection process this step is called to update the file
9
+ # to be used as a the banner for the collection.
10
+ #
11
+ class SaveCollectionBanner
12
+ include Dry::Transaction::Operation
13
+
14
+ ##
15
+ # @param [Hyrax::ChangeSet] change_set
16
+ # @param [Array<Integer>] update_banner_file_ids
17
+ # @param [Boolean] banner_unchanged_indicator
18
+ #
19
+ # @return [Dry::Monads::Result] `Failure` if the banner info fails to save;
20
+ # `Success(input)`, otherwise.
21
+ def call(collection_resource, update_banner_file_ids: nil, banner_unchanged_indicator: true)
22
+ return Success(collection_resource) if ActiveModel::Type::Boolean.new.cast(banner_unchanged_indicator)
23
+ collection_id = collection_resource.id.to_s
24
+ process_banner_input(collection_id: collection_id, update_banner_file_ids: update_banner_file_ids)
25
+ Success(collection_resource)
26
+ end
27
+
28
+ private
29
+
30
+ def process_banner_input(collection_id:, update_banner_file_ids:)
31
+ remove_banner(collection_id: collection_id)
32
+ add_new_banner(collection_id: collection_id, uploaded_file_ids: update_banner_file_ids) if update_banner_file_ids
33
+ end
34
+
35
+ def remove_banner(collection_id:)
36
+ banner_info = CollectionBrandingInfo.where(collection_id: collection_id).where(role: "banner")
37
+ banner_info&.delete_all
38
+ end
39
+
40
+ def add_new_banner(collection_id:, uploaded_file_ids:)
41
+ f = uploaded_files(uploaded_file_ids).first
42
+ banner_info = CollectionBrandingInfo.new(
43
+ collection_id: collection_id,
44
+ filename: File.split(f.file_url).last,
45
+ role: "banner",
46
+ alt_txt: "",
47
+ target_url: ""
48
+ )
49
+ banner_info.save f.file_url
50
+ end
51
+
52
+ def uploaded_files(uploaded_file_ids)
53
+ return [] if uploaded_file_ids.empty?
54
+ UploadedFile.find(uploaded_file_ids)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+ module Hyrax
3
+ module Transactions
4
+ module Steps
5
+ ##
6
+ # Adds logo info via `ChangeSet`.
7
+ #
8
+ # During the update collection process this step is called to update the file(s)
9
+ # to be used as logo(s) for the collection.
10
+ #
11
+ class SaveCollectionLogo
12
+ include Dry::Transaction::Operation
13
+
14
+ ##
15
+ # @param [Hyrax::ChangeSet] change_set
16
+ # @param [Array<#Integer>] update_logo_file_ids
17
+ # @param [Array<String>] alttext_values
18
+ # @param [Array<String>] linkurl_values
19
+ #
20
+ # @return [Dry::Monads::Result] `Failure` if the work fails to save;
21
+ # `Success(input)`, otherwise.
22
+ def call(collection_resource, update_logo_file_ids: nil, alttext_values: nil, linkurl_values: nil)
23
+ collection_id = collection_resource.id.to_s
24
+ process_logo_input(collection_id: collection_id, update_logo_file_ids: update_logo_file_ids, alttext_values: alttext_values, linkurl_values: linkurl_values)
25
+ Success(collection_resource)
26
+ end
27
+
28
+ private
29
+
30
+ def process_logo_input(collection_id:, update_logo_file_ids:, alttext_values:, linkurl_values:)
31
+ uploaded_file_ids = update_logo_file_ids
32
+ public_files = []
33
+
34
+ if uploaded_file_ids.nil?
35
+ # all logo files were removed, so delete all files previously uploaded
36
+ remove_redundant_files(collection_id: collection_id, public_files: public_files)
37
+ return
38
+ end
39
+
40
+ public_files = process_logo_records(collection_id: collection_id, uploaded_file_ids: uploaded_file_ids, alttext_values: alttext_values, linkurl_values: linkurl_values)
41
+ remove_redundant_files(collection_id: collection_id, public_files: public_files)
42
+ end
43
+
44
+ def process_logo_records(collection_id:, uploaded_file_ids:, alttext_values:, linkurl_values:)
45
+ public_files = []
46
+ uploaded_file_ids.each_with_index do |ufi, i|
47
+ # If the user has chosen a new logo, the ufi will be an integer
48
+ # If the logo was previously chosen, the ufi will be a path
49
+ # If it is a path, update the rec, else create a new rec
50
+ if !ufi.match(/\D/).nil?
51
+ update_logo_info(collection_id: collection_id, uploaded_file_id: ufi, alttext: alttext_values[i], linkurl: verify_linkurl(linkurl_values[i]))
52
+ public_files << ufi
53
+ else # brand new one, insert in the database
54
+ logo_info = create_logo_info(collection_id: collection_id, uploaded_file_id: ufi, alttext: alttext_values[i], linkurl: verify_linkurl(linkurl_values[i]))
55
+ public_files << logo_info.local_path
56
+ end
57
+ end
58
+ public_files
59
+ end
60
+
61
+ def update_logo_info(collection_id:, uploaded_file_id:, alttext:, linkurl:)
62
+ logo_info = CollectionBrandingInfo.where(collection_id: collection_id).where(role: "logo").where(local_path: uploaded_file_id.to_s).first
63
+ logo_info.alt_text = alttext
64
+ logo_info.target_url = linkurl
65
+ logo_info.local_path = uploaded_file_id
66
+ logo_info.save(uploaded_file_id, false)
67
+ end
68
+
69
+ def create_logo_info(collection_id:, uploaded_file_id:, alttext:, linkurl:)
70
+ file = uploaded_files(uploaded_file_id)
71
+ logo_info = CollectionBrandingInfo.new(
72
+ collection_id: collection_id,
73
+ filename: File.split(file.file_url).last,
74
+ role: "logo",
75
+ alt_txt: alttext,
76
+ target_url: linkurl
77
+ )
78
+ logo_info.save file.file_url
79
+ logo_info
80
+ end
81
+
82
+ def uploaded_files(uploaded_file_ids)
83
+ return [] if uploaded_file_ids.empty?
84
+ UploadedFile.find(uploaded_file_ids)
85
+ end
86
+
87
+ def remove_redundant_files(collection_id:, public_files:)
88
+ # remove any public ones that were not included in the selection.
89
+ logos_info = CollectionBrandingInfo.where(collection_id: collection_id).where(role: "logo")
90
+ logos_info.each do |logo_info|
91
+ logo_info.delete(logo_info.local_path) unless public_files.include? logo_info.local_path
92
+ logo_info.destroy unless public_files.include? logo_info.local_path
93
+ end
94
+ end
95
+
96
+ # Only accept HTTP|HTTPS urls;
97
+ # @return <String> the url
98
+ def verify_linkurl(linkurl)
99
+ url = Loofah.scrub_fragment(linkurl, :prune).to_s
100
+ url if valid_url?(url)
101
+ end
102
+
103
+ def valid_url?(url)
104
+ (url =~ URI.regexp(['http', 'https']))
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -18,6 +18,9 @@ module Hyrax
18
18
  # step.call(work).or { |err| puts err.messages }
19
19
  #
20
20
  # @since 2.4.0
21
+ # @deprecated This is part of the legacy AF set of transaction steps for works.
22
+ # Transactions are not being used with AF works. This will be removed in 4.0.
23
+ # @see Hyrax::Transactions::Steps::Save
21
24
  class SaveWork
22
25
  include Dry::Transaction::Operation
23
26
 
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+ require 'dry/monads'
3
+
4
+ module Hyrax
5
+ module Transactions
6
+ module Steps
7
+ ##
8
+ # Add a given `::User` as the `#creator` via a ChangeSet.
9
+ #
10
+ # If no user is given, simply passes as a `Success`.
11
+ #
12
+ # @since 3.0.0
13
+ class SetUserAsCreator
14
+ include Dry::Monads[:result]
15
+
16
+ ##
17
+ # @param [Hyrax::ChangeSet] change_set
18
+ # @param [#user_key] user
19
+ #
20
+ # @return [Dry::Monads::Result]
21
+ def call(change_set, user: NullUser.new)
22
+ change_set.creator = [user.user_key] if user.user_key
23
+
24
+ Success(change_set)
25
+ rescue NoMethodError => err
26
+ Failure([err.message, change_set])
27
+ end
28
+
29
+ ##
30
+ # @api private
31
+ class NullUser
32
+ ##
33
+ # @return [nil]
34
+ def user_key
35
+ nil
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+ require 'dry/monads'
3
+
4
+ module Hyrax
5
+ module Transactions
6
+ module Steps
7
+ ##
8
+ # Adds and removes work members
9
+ class UpdateWorkMembers
10
+ include Dry::Monads[:result]
11
+
12
+ ##
13
+ # @param [Hyrax::Work] obj
14
+ # @param [Hash] work_members_attributes
15
+ #
16
+ # @return [Dry::Monads::Result]
17
+ def call(obj, work_members_attributes: nil, user: nil)
18
+ return Success(obj) if work_members_attributes.blank?
19
+
20
+ attributes = extract_attributes(work_members_attributes)
21
+ current_member_ids = obj.member_ids.map(&:id)
22
+ destroys = attributes.select do |v|
23
+ ActiveModel::Type::Boolean.new.cast(v['_destroy'])
24
+ end
25
+
26
+ inserts = (attributes - destroys).map { |h| h['id'] }.compact - current_member_ids
27
+ destroys = destroys.map { |h| h['id'] }.compact & current_member_ids
28
+ obj.member_ids += inserts.map { |id| Valkyrie::ID.new(id) }
29
+ obj.member_ids -= destroys.map { |id| Valkyrie::ID.new(id) }
30
+
31
+ save_resource(obj, user)
32
+ Success(obj)
33
+ end
34
+
35
+ private
36
+
37
+ def extract_attributes(attribute_hash)
38
+ attribute_hash
39
+ .sort_by { |i, _| i.to_i }
40
+ .map { |_, attributes| attributes }
41
+ end
42
+
43
+ def save_resource(obj, user)
44
+ saved = Hyrax.persister.save(resource: obj)
45
+ user ||= ::User.find_by_user_key(obj.depositor)
46
+ Hyrax.publisher.publish('object.metadata.updated', object: saved, user: user)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -3,10 +3,11 @@ module Hyrax
3
3
  module Transactions
4
4
  ##
5
5
  # @since 3.0.0
6
+ # @deprecated Use Hyrax::Transactions::WorkUpdate instead.
6
7
  class UpdateWork < Transaction
7
- DEFAULT_STEPS = ['change_set.apply',
8
- 'work_resource.save_acl',
9
- 'work_resource.add_file_sets'].freeze
8
+ DEFAULT_STEPS = Hyrax::Transactions::WorkUpdate::DEFAULT_STEPS
9
+
10
+ # DO NOT USE - This class is deprecated. Use Hyrax::Transactions::WorkUpdate instead.
10
11
 
11
12
  ##
12
13
  # @see Hyrax::Transactions::Transaction
@@ -11,10 +11,10 @@ module Hyrax
11
11
  DEFAULT_STEPS = ['change_set.set_default_admin_set',
12
12
  'change_set.ensure_admin_set',
13
13
  'change_set.set_user_as_depositor',
14
- 'change_set.add_to_collections',
15
14
  'change_set.apply',
16
15
  'work_resource.save_acl',
17
16
  'work_resource.add_file_sets',
17
+ 'work_resource.change_depositor',
18
18
  'work_resource.add_to_parent'].freeze
19
19
 
20
20
  ##
@@ -8,7 +8,8 @@ module Hyrax
8
8
  #
9
9
  # @since 3.0.0
10
10
  class WorkDestroy < Transaction
11
- DEFAULT_STEPS = ['work_resource.delete'].freeze
11
+ DEFAULT_STEPS = ['work_resource.delete',
12
+ 'work_resource.delete_acl'].freeze
12
13
 
13
14
  ##
14
15
  # @see Hyrax::Transactions::Transaction
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ module Hyrax
3
+ module Transactions
4
+ ##
5
+ # @since 3.4.0
6
+ class WorkUpdate < Transaction
7
+ DEFAULT_STEPS = ['change_set.apply',
8
+ 'work_resource.save_acl',
9
+ 'work_resource.add_file_sets',
10
+ 'work_resource.update_work_members'].freeze
11
+
12
+ ##
13
+ # @see Hyrax::Transactions::Transaction
14
+ def initialize(container: Container, steps: DEFAULT_STEPS)
15
+ super
16
+ end
17
+ end
18
+ end
19
+ end
data/lib/hyrax/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Hyrax
3
- VERSION = '3.3.0'
3
+ VERSION = '3.4.2'
4
4
  end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wings
4
+ class ActiveFedoraConverter
5
+ def self.FileMetadataNode(resource_class) # rubocop:disable Naming/MethodName
6
+ class_cache[resource_class] ||= Class.new(FileMetadataNode) do
7
+ self.valkyrie_class = resource_class
8
+
9
+ # skip reserved attributes, we assume we don't need to translate valkyrie internals
10
+ schema = resource_class.schema.reject do |key|
11
+ resource_class.reserved_attributes.include?(key.name) ||
12
+ key.name == :size
13
+ end
14
+
15
+ Wings::ActiveFedoraConverter.apply_properties(self, schema)
16
+ end
17
+ end
18
+ end
19
+
20
+ class FileMetadataNode < ActiveFedora::Base
21
+ property :file_set_id, predicate: ::RDF::URI.intern("http://hyrax.samvera.org/ns/wings#file_set_id")
22
+ property :file_identifier, predicate: ::RDF::URI.intern("http://hyrax.samvera.org/ns/wings#file_identifier")
23
+
24
+ class_attribute :valkyrie_class
25
+
26
+ class << self
27
+ def model_name(*)
28
+ Hyrax::Name.new(valkyrie_class)
29
+ end
30
+
31
+ def to_rdf_representation
32
+ "Wings(#{valkyrie_class})"
33
+ end
34
+ alias inspect to_rdf_representation
35
+ alias to_s inspect
36
+ end
37
+
38
+ def indexing_service
39
+ Hyrax::ValkyrieIndexer.for(resource: valkyrie_resource)
40
+ end
41
+
42
+ def to_solr
43
+ super.tap do |doc|
44
+ doc[:file_identifier_ssim] = file_identifier
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wings
4
+ class ActiveFedoraConverter
5
+ ##
6
+ # Constructs an instance for the given converter. +converter+ must provide
7
+ # an +id+, +resource+, and +active_fedora_class+.
8
+ #
9
+ # This interface allows handling for special cases based on the target
10
+ # class, instance data for +resource+, or the id format. This originated as
11
+ # an extraction of some such special handling from the converter code.
12
+ class InstanceBuilder
13
+ ##
14
+ # @!attribute [r] converter
15
+ # @return [#active_fedora_class, #id, #resource]
16
+ # @!attribute [r] resource
17
+ # @return [Valkyrie::Resource]
18
+ attr_reader :converter, :resource
19
+
20
+ ##
21
+ # @param [#active_fedora_class, #id, #resource]
22
+ def initialize(converter)
23
+ @converter = converter
24
+ @resource = converter.resource
25
+ end
26
+
27
+ ##
28
+ # @return [ActiveFedora::Common]
29
+ def build
30
+ if builds_file_metadata? && !builds_metadata_for_active_fedora_file?
31
+ # convert to a generic/generated FileMetadataNode class with
32
+ # properties matching the source class
33
+ Wings::ActiveFedoraConverter::FileMetadataNode(resource.class)
34
+ .new(file_identifier: Array(resource.file_identifier)
35
+ .map(&:to_s))
36
+ elsif converter.id.present?
37
+ converter.active_fedora_class.find(converter.id)
38
+ else
39
+ converter.active_fedora_class.new
40
+ end
41
+ rescue ActiveFedora::ObjectNotFoundError
42
+ converter.active_fedora_class.new
43
+ end
44
+
45
+ ##
46
+ # @return [Boolean]
47
+ def builds_file_metadata?
48
+ resource.try(:file_identifier).present?
49
+ end
50
+
51
+ ##
52
+ # @return [Boolean]
53
+ def builds_metadata_for_active_fedora_file?
54
+ return false unless builds_file_metadata?
55
+
56
+ adapter_for_file = begin
57
+ ::Valkyrie::StorageAdapter.adapter_for(id: resource.file_identifier)
58
+ rescue ::Valkyrie::StorageAdapter::AdapterNotFoundError => err
59
+ Hyrax.logger.warn "Processing a FileMetadata (id: #{converter.id}) referencing " \
60
+ "a file #{resource.file_identifier}; could not find a " \
61
+ "storage adapter to handle that file.\n\t#{err.message}"
62
+ end
63
+
64
+ adapter_for_file.is_a?(::Valkyrie::Storage::Fedora)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'wings/converter_value_mapper'
4
4
  require 'wings/active_fedora_converter/default_work'
5
+ require 'wings/active_fedora_converter/file_metadata_node'
6
+ require 'wings/active_fedora_converter/instance_builder'
5
7
  require 'wings/active_fedora_converter/nested_resource'
6
8
 
7
9
  module Wings
@@ -100,9 +102,7 @@ module Wings
100
102
  private
101
103
 
102
104
  def instance
103
- id.present? ? active_fedora_class.find(id) : active_fedora_class.new
104
- rescue ActiveFedora::ObjectNotFoundError
105
- active_fedora_class.new
105
+ InstanceBuilder.new(self).build
106
106
  end
107
107
 
108
108
  def attributes_class
@@ -58,7 +58,11 @@ module Wings
58
58
  end
59
59
 
60
60
  attributes[:original_filename] = obj.original_name
61
- attributes[:file_identifier] = obj.id if obj.id.present?
61
+
62
+ if obj.id.present?
63
+ uri = Hyrax.config.translate_id_to_uri.call(obj.id)
64
+ attributes[:file_identifier] = Wings::Valkyrie::Storage.cast_to_valkyrie_id(uri)
65
+ end
62
66
  attributes[:type] = obj.metadata_node.type.to_a
63
67
  attributes[:size] = obj.size
64
68
  attributes
@@ -33,7 +33,20 @@ module Wings
33
33
  #
34
34
  # @raise [Hyrax::ObjectNotFoundError]
35
35
  def find_file_metadata_by(id:, use_valkyrie: true)
36
- find_file_metadata_by_alternate_identifier(alternate_identifier: id, use_valkyrie: use_valkyrie)
36
+ fcrepo_flag =
37
+ begin
38
+ ::Valkyrie::StorageAdapter.adapter_for(id: id).is_a?(::Valkyrie::Storage::Fedora)
39
+ rescue ::Valkyrie::StorageAdapter::AdapterNotFoundError
40
+ true # assume fcrepo if we can't find an adapter
41
+ end
42
+
43
+ if fcrepo_flag
44
+ find_file_metadata_by_alternate_identifier(alternate_identifier: id, use_valkyrie: use_valkyrie)
45
+ else
46
+ result = ActiveFedora::Base.where(file_identifier_ssim: id.to_s).first ||
47
+ raise(Hyrax::ObjectNotFoundError)
48
+ result.valkyrie_resource
49
+ end
37
50
  end
38
51
 
39
52
  # Find a Hyrax::FileMetadata using an alternate ID, and map it to a
@@ -48,8 +61,8 @@ module Wings
48
61
  #
49
62
  # @raise [Hyrax::ObjectNotFoundError]
50
63
  def find_file_metadata_by_alternate_identifier(alternate_identifier:, use_valkyrie: true)
51
- alternate_identifier = ::Valkyrie::ID.new(alternate_identifier)
52
- object = Hydra::PCDM::File.find(alternate_identifier.to_s)
64
+ alternate_identifier = ::Valkyrie::ID.new(alternate_identifier).to_s
65
+ object = Hydra::PCDM::File.find(alternate_identifier)
53
66
  raise Hyrax::ObjectNotFoundError if object.new_record?
54
67
 
55
68
  if use_valkyrie == false
@@ -73,11 +86,9 @@ module Wings
73
86
  # if there are no ids or none of the ids map to Hyrax::FileMetadata
74
87
  def find_many_file_metadata_by_ids(ids:, use_valkyrie: true)
75
88
  ids.each_with_object([]) do |alt_id, results|
76
- begin
77
- results << find_file_metadata_by_alternate_identifier(alternate_identifier: alt_id, use_valkyrie: use_valkyrie)
78
- rescue Hyrax::ObjectNotFoundError
79
- next
80
- end
89
+ results << find_file_metadata_by_alternate_identifier(alternate_identifier: alt_id, use_valkyrie: use_valkyrie)
90
+ rescue Hyrax::ObjectNotFoundError
91
+ next
81
92
  end
82
93
  end
83
94