hyrax 5.0.1 → 5.0.3

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 (247) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +7 -176
  3. data/.dassie/.env +8 -3
  4. data/.dassie/Gemfile +13 -2
  5. data/.dassie/app/controllers/hyrax/generic_work_resources_controller.rb +17 -0
  6. data/.dassie/app/controllers/hyrax/generic_works_controller.rb +7 -1
  7. data/.dassie/app/forms/generic_work_resource_form.rb +20 -0
  8. data/.dassie/app/indexers/generic_work_resource_indexer.rb +16 -0
  9. data/.dassie/app/models/admin_set_resource.rb +9 -0
  10. data/.dassie/app/models/collection_resource.rb +2 -0
  11. data/.dassie/app/models/file_set.rb +2 -0
  12. data/.dassie/app/models/generic_work_resource.rb +10 -0
  13. data/.dassie/app/views/hyrax/generic_work_resources/_generic_work_resource.html.erb +2 -0
  14. data/.dassie/config/analytics.yml +6 -1
  15. data/.dassie/config/application.rb +24 -0
  16. data/.dassie/config/initializers/hyrax.rb +13 -3
  17. data/.dassie/config/initializers/wings.rb +109 -0
  18. data/.dassie/config/metadata/generic_work_resource.yaml +22 -0
  19. data/.dassie/config/valkyrie_index.yml +4 -10
  20. data/.dassie/db/migrate/20240506070809_valkyrie_id_to_string.rb +5 -0
  21. data/.dassie/db/schema.rb +2 -2
  22. data/.dassie/spec/indexers/generic_work_resource_indexer_spec.rb +13 -0
  23. data/.dassie/spec/models/generic_work_resource_spec.rb +12 -0
  24. data/.dassie/spec/views/generic_work_resources/_generic_work_resource.html.erb_spec.rb +7 -0
  25. data/.dockerignore +6 -4
  26. data/.github/release.yml +3 -0
  27. data/.github/workflows/lint-build-test.yml +130 -0
  28. data/.github/workflows/test-results.yml +40 -0
  29. data/.koppie/.env +7 -5
  30. data/.koppie/Gemfile +12 -1
  31. data/.koppie/config/analytics.yml +6 -1
  32. data/.koppie/config/environments/test.rb +2 -0
  33. data/.koppie/config/initializers/1_valkyrie.rb +6 -2
  34. data/.koppie/config/solr.yml +1 -1
  35. data/.regen +1 -1
  36. data/.rubocop.yml +5 -0
  37. data/Dockerfile +16 -36
  38. data/Gemfile +2 -0
  39. data/app/assets/javascripts/hydra-editor/field_manager.es6 +187 -0
  40. data/app/assets/javascripts/hyrax/analytics_events.js +48 -24
  41. data/app/assets/javascripts/hyrax/collapse.js +4 -4
  42. data/app/assets/javascripts/hyrax/file_manager/save_manager.es6 +2 -0
  43. data/app/assets/javascripts/hyrax/search.js +2 -3
  44. data/app/assets/javascripts/hyrax/select_work_type.es6 +3 -1
  45. data/app/assets/javascripts/hyrax/uploader.js +20 -18
  46. data/app/assets/javascripts/hyrax.js +1 -0
  47. data/app/assets/stylesheets/_bootstrap-default-overrides.scss +4 -0
  48. data/app/assets/stylesheets/hyrax/_card.scss +4 -0
  49. data/app/assets/stylesheets/hyrax/_catalog.scss +21 -0
  50. data/app/assets/stylesheets/hyrax/_collections.scss +1 -1
  51. data/app/assets/stylesheets/hyrax/_facets.scss +15 -3
  52. data/app/assets/stylesheets/hyrax/_featured.scss +4 -0
  53. data/app/assets/stylesheets/hyrax/_form.scss +4 -0
  54. data/app/assets/stylesheets/hyrax/_forms.scss +2 -1
  55. data/app/assets/stylesheets/hyrax/_nestable.scss +9 -8
  56. data/app/assets/stylesheets/hyrax/_select_work_type.scss +12 -0
  57. data/app/assets/stylesheets/hyrax/_styles.scss +4 -0
  58. data/app/assets/stylesheets/hyrax/_work-show.scss +3 -0
  59. data/app/controllers/concerns/hyrax/singular_subresource_controller.rb +7 -2
  60. data/app/controllers/concerns/hyrax/valkyrie_downloads_controller_behavior.rb +11 -2
  61. data/app/controllers/concerns/hyrax/works_controller_behavior.rb +9 -2
  62. data/app/controllers/hyrax/admin/analytics/collection_reports_controller.rb +2 -2
  63. data/app/controllers/hyrax/admin/analytics/work_reports_controller.rb +7 -8
  64. data/app/controllers/hyrax/dashboard/collections_controller.rb +2 -1
  65. data/app/controllers/hyrax/downloads_controller.rb +24 -3
  66. data/app/controllers/hyrax/file_sets_controller.rb +32 -6
  67. data/app/controllers/hyrax/my/works_controller.rb +20 -0
  68. data/app/controllers/hyrax/stats_controller.rb +1 -1
  69. data/app/controllers/hyrax/uploads_controller.rb +28 -2
  70. data/app/forms/hyrax/forms/admin/appearance.rb +1 -1
  71. data/app/forms/hyrax/forms/admin/collection_type_form.rb +1 -7
  72. data/app/forms/hyrax/forms/pcdm_collection_form.rb +9 -0
  73. data/app/forms/hyrax/forms/work_embargo_form.rb +6 -0
  74. data/app/forms/hyrax/forms/work_lease_form.rb +6 -0
  75. data/app/indexers/concerns/hyrax/location_indexer.rb +2 -2
  76. data/app/indexers/hyrax/indexers/file_set_indexer.rb +4 -0
  77. data/app/indexers/hyrax/indexers/resource_indexer.rb +1 -0
  78. data/app/indexers/hyrax/valkyrie_indexer.rb +3 -5
  79. data/app/jobs/migrate_files_to_valkyrie_job.rb +109 -0
  80. data/app/jobs/migrate_resources_job.rb +34 -0
  81. data/app/jobs/valkyrie_create_derivatives_job.rb +2 -1
  82. data/app/models/admin_set.rb +1 -0
  83. data/app/models/concerns/hyrax/ar_resource.rb +104 -0
  84. data/app/models/concerns/hyrax/solr_document/ordered_members.rb +2 -1
  85. data/app/models/concerns/hyrax/solr_document_behavior.rb +13 -2
  86. data/app/models/concerns/hyrax/valkyrie_lazy_migration.rb +82 -0
  87. data/app/models/file_download_stat.rb +1 -1
  88. data/app/models/file_view_stat.rb +1 -1
  89. data/app/models/hyrax/collection_type.rb +12 -4
  90. data/app/models/hyrax/file_metadata.rb +19 -0
  91. data/app/models/hyrax/file_set.rb +25 -0
  92. data/app/models/hyrax/model_registry.rb +2 -3
  93. data/app/models/hyrax/resource.rb +5 -0
  94. data/app/models/hyrax/statistic.rb +12 -37
  95. data/app/presenters/hyrax/file_set_presenter.rb +2 -1
  96. data/app/presenters/hyrax/file_usage.rb +3 -3
  97. data/app/presenters/hyrax/iiif_manifest_presenter.rb +2 -1
  98. data/app/presenters/hyrax/member_presenter_factory.rb +7 -1
  99. data/app/presenters/hyrax/menu_presenter.rb +1 -1
  100. data/app/presenters/hyrax/stats_usage_presenter.rb +2 -1
  101. data/app/presenters/hyrax/work_show_presenter.rb +13 -17
  102. data/app/presenters/hyrax/work_usage.rb +5 -2
  103. data/app/search_builders/hyrax/expired_embargo_search_builder.rb +7 -1
  104. data/app/search_builders/hyrax/expired_lease_search_builder.rb +7 -1
  105. data/app/search_builders/hyrax/filter_by_type.rb +1 -3
  106. data/app/search_builders/hyrax/valkyrie_abstract_type_relation.rb +7 -2
  107. data/app/services/hyrax/access_control_list.rb +1 -1
  108. data/app/services/hyrax/admin_set_create_service.rb +16 -5
  109. data/app/services/hyrax/admin_set_service.rb +2 -1
  110. data/app/services/hyrax/analytics/ga4/base.rb +96 -0
  111. data/app/services/hyrax/analytics/ga4/events.rb +25 -0
  112. data/app/services/hyrax/analytics/ga4/events_daily.rb +36 -0
  113. data/app/services/hyrax/analytics/ga4/visits.rb +33 -0
  114. data/app/services/hyrax/analytics/ga4/visits_daily.rb +24 -0
  115. data/app/services/hyrax/analytics/ga4.rb +204 -0
  116. data/app/services/hyrax/analytics/google.rb +16 -2
  117. data/app/services/hyrax/analytics/matomo.rb +16 -3
  118. data/app/services/hyrax/analytics/results.rb +6 -0
  119. data/app/services/hyrax/custom_queries/find_access_control.rb +1 -1
  120. data/app/services/hyrax/custom_queries/find_by_date_range.rb +6 -23
  121. data/app/services/hyrax/custom_queries/find_collections_by_type.rb +2 -2
  122. data/app/services/hyrax/custom_queries/find_count_by.rb +3 -31
  123. data/app/services/hyrax/custom_queries/find_file_metadata.rb +2 -2
  124. data/app/services/hyrax/custom_queries/find_models_by_access.rb +5 -27
  125. data/app/services/hyrax/embargo_manager.rb +2 -1
  126. data/app/services/hyrax/listeners/file_listener.rb +2 -2
  127. data/app/services/hyrax/lock_manager.rb +6 -6
  128. data/app/services/hyrax/lockable.rb +4 -3
  129. data/app/services/hyrax/simple_schema_loader.rb +1 -1
  130. data/app/services/hyrax/solr_service.rb +22 -8
  131. data/app/services/hyrax/statistics/query_service.rb +1 -1
  132. data/app/services/hyrax/statistics/works/over_time.rb +1 -1
  133. data/app/services/hyrax/thumbnail_path_service.rb +2 -0
  134. data/app/services/hyrax/user_stat_importer.rb +5 -5
  135. data/app/services/hyrax/valkyrie_upload.rb +9 -7
  136. data/app/services/hyrax/versioning_service.rb +10 -2
  137. data/app/services/hyrax/work_query_service.rb +2 -2
  138. data/app/services/migrate_resource_service.rb +55 -0
  139. data/app/views/_controls.html.erb +5 -5
  140. data/app/views/_masthead.html.erb +1 -1
  141. data/app/views/catalog/_search_form.html.erb +9 -16
  142. data/app/views/catalog/_thumbnail_list_collection.html.erb +1 -1
  143. data/app/views/catalog/_thumbnail_list_default.html.erb +2 -2
  144. data/app/views/hyrax/admin/analytics/collection_reports/index.html.erb +4 -4
  145. data/app/views/hyrax/admin/analytics/work_reports/index.html.erb +1 -1
  146. data/app/views/hyrax/admin/collection_types/_form.html.erb +4 -4
  147. data/app/views/hyrax/admin/collection_types/index.html.erb +1 -1
  148. data/app/views/hyrax/admin/features/index.html.erb +1 -1
  149. data/app/views/hyrax/base/_file_manager_actions.html.erb +1 -1
  150. data/app/views/hyrax/base/_file_manager_member.html.erb +7 -4
  151. data/app/views/hyrax/base/_file_manager_thumbnail.html.erb +1 -1
  152. data/app/views/hyrax/base/_form_files.html.erb +1 -1
  153. data/app/views/hyrax/base/_form_member_of_collections.html.erb +4 -0
  154. data/app/views/hyrax/base/_show_actions.html.erb +7 -8
  155. data/app/views/hyrax/base/_work_button_row.html.erb +1 -1
  156. data/app/views/hyrax/batch_select/_add_button.html.erb +1 -1
  157. data/app/views/hyrax/content_blocks/_form.html.erb +3 -3
  158. data/app/views/hyrax/dashboard/_sidebar.html.erb +1 -1
  159. data/app/views/hyrax/dashboard/_user_activity.html.erb +2 -2
  160. data/app/views/hyrax/dashboard/collections/_form.html.erb +4 -4
  161. data/app/views/hyrax/dashboard/collections/_form_share.html.erb +6 -4
  162. data/app/views/hyrax/dashboard/collections/_list_collections.html.erb +1 -1
  163. data/app/views/hyrax/dashboard/collections/_show_document_list_row.html.erb +1 -1
  164. data/app/views/hyrax/dashboard/show_admin.html.erb +18 -19
  165. data/app/views/hyrax/dashboard/sidebar/_activity.html.erb +1 -1
  166. data/app/views/hyrax/embargoes/_list_expired_active_embargoes.html.erb +7 -7
  167. data/app/views/hyrax/file_sets/_actions.html.erb +9 -1
  168. data/app/views/hyrax/file_sets/_permission_form.html.erb +4 -2
  169. data/app/views/hyrax/file_sets/_show_actions.html.erb +1 -1
  170. data/app/views/hyrax/homepage/_featured.html.erb +1 -1
  171. data/app/views/hyrax/homepage/_recent_document.html.erb +2 -2
  172. data/app/views/hyrax/leases/_list_expired_active_leases.html.erb +6 -6
  173. data/app/views/hyrax/my/collections/_list_collections.html.erb +1 -1
  174. data/app/views/hyrax/my/collections/_tabs.html.erb +1 -1
  175. data/app/views/hyrax/pages/_form.html.erb +8 -8
  176. data/app/views/hyrax/transfers/_received.html.erb +1 -1
  177. data/app/views/hyrax/uploads/create.json.jbuilder +2 -2
  178. data/app/views/hyrax/users/_activity_log.html.erb +15 -9
  179. data/app/views/hyrax/users/_user_row.html.erb +6 -3
  180. data/app/views/hyrax/users/_vitals.html.erb +3 -2
  181. data/app/views/layouts/_head_tag_content.html.erb +2 -0
  182. data/app/views/shared/_appearance_styles.html.erb +5 -1
  183. data/app/views/shared/_ga4.html.erb +11 -0
  184. data/app/views/shared/_select_work_type_modal.html.erb +10 -1
  185. data/bin/db-migrate-seed.sh +3 -3
  186. data/bin/dev-entrypoint.sh +7 -2
  187. data/bin/{db-wait.sh → service-wait.sh} +1 -1
  188. data/bin/worker-entrypoint.sh +8 -0
  189. data/chart/hyrax/templates/deployment-worker.yaml +2 -2
  190. data/config/locales/hyrax.en.yml +4 -2
  191. data/config/metadata/basic_metadata.yaml +20 -0
  192. data/config/metadata/hyrax_internal_metadata.yaml +1 -1
  193. data/docker-compose-dassie.yml +167 -0
  194. data/docker-compose-koppie.yml +21 -36
  195. data/docker-compose-sirenia.yml +50 -44
  196. data/docker-compose.yml +2 -183
  197. data/documentation/developing-your-hyrax-based-app.md +2 -2
  198. data/hyrax.gemspec +5 -4
  199. data/lib/freyja/custom_query_container.rb +5 -0
  200. data/lib/freyja/metadata_adapter.rb +32 -0
  201. data/lib/freyja/persister.rb +42 -0
  202. data/lib/freyja/query_service.rb +20 -0
  203. data/lib/freyja/resource_factory.rb +8 -0
  204. data/lib/freyja.rb +14 -0
  205. data/lib/frigg/custom_query_container.rb +5 -0
  206. data/lib/frigg/metadata_adapter.rb +22 -0
  207. data/lib/frigg/persister.rb +33 -0
  208. data/lib/frigg/query_service.rb +15 -0
  209. data/lib/frigg.rb +13 -0
  210. data/lib/generators/hyrax/install_generator.rb +5 -0
  211. data/lib/generators/hyrax/templates/config/analytics.yml +6 -1
  212. data/lib/generators/hyrax/templates/config/initializers/1_valkyrie.rb +6 -2
  213. data/lib/generators/hyrax/templates/config/valkyrie_index.yml +1 -1
  214. data/lib/goddess/custom_query_container.rb +71 -0
  215. data/lib/goddess/metadata.rb +13 -0
  216. data/lib/goddess/query.rb +176 -0
  217. data/lib/hyrax/configuration.rb +83 -0
  218. data/lib/hyrax/engine.rb +2 -0
  219. data/lib/hyrax/form_fields.rb +1 -3
  220. data/lib/hyrax/name.rb +5 -0
  221. data/lib/hyrax/rubocop/custom_cops.rb +30 -0
  222. data/lib/hyrax/specs/capybara.rb +10 -6
  223. data/lib/hyrax/specs/shared_specs/factories/admin_sets.rb +2 -0
  224. data/lib/hyrax/specs/shared_specs/factories/hyrax_embargo.rb +4 -0
  225. data/lib/hyrax/specs/shared_specs/factories/hyrax_lease.rb +4 -0
  226. data/lib/hyrax/specs/shared_specs/factories/hyrax_work.rb +16 -2
  227. data/lib/hyrax/specs/shared_specs/hydra_works.rb +1 -1
  228. data/lib/hyrax/transactions/admin_set_destroy.rb +2 -1
  229. data/lib/hyrax/transactions/collection_destroy.rb +2 -1
  230. data/lib/hyrax/transactions/container.rb +9 -0
  231. data/lib/hyrax/transactions/steps/add_file_sets.rb +2 -1
  232. data/lib/hyrax/transactions/steps/delete_permission_template.rb +30 -0
  233. data/lib/hyrax/transactions/steps/delete_resource.rb +1 -1
  234. data/lib/hyrax/transactions/steps/save_collection_logo.rb +2 -1
  235. data/lib/hyrax/valkyrie_can_can_adapter.rb +8 -1
  236. data/lib/hyrax/version.rb +1 -1
  237. data/lib/wings/active_fedora_converter.rb +13 -5
  238. data/lib/wings/converter_value_mapper.rb +1 -0
  239. data/lib/wings/services/custom_queries/find_collections_by_type.rb +2 -1
  240. data/lib/wings/services/custom_queries/find_file_metadata.rb +2 -2
  241. data/lib/wings/setup.rb +12 -3
  242. data/lib/wings/transformer_value_mapper.rb +5 -1
  243. data/lib/wings/valkyrie/persister.rb +3 -1
  244. data/template.rb +1 -1
  245. metadata +77 -19
  246. data/.koppie/scripts/db-migrate-seed.sh +0 -9
  247. data/.koppie/scripts/entrypoint.sh +0 -10
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+ module Goddess
3
+ module Query
4
+ ##
5
+ # This module provides the mechanisms for the four different query strategies:
6
+ #
7
+ # - {#find_multiple}
8
+ # - {#find_single} :: find an instance and if none is found, raise an exception
9
+ # - {#count_multiple}
10
+ # - {#find_single_or_nil} :: as {#find_single} but if no instance is found return nil
11
+ #
12
+ # These private methods are responsible for querying the various inner services of the
13
+ # QueryService adapter.
14
+ module MethodMissingMachinations
15
+ def model_class_for(model)
16
+ internal_resource = model.respond_to?(:internal_resource) ? model.internal_resource : nil
17
+ internal_resource&.safe_constantize || Wings::ModelRegistry.lookup(model)
18
+ end
19
+
20
+ def setup_model(model_name)
21
+ model_name = model_class_for(model_name)
22
+ model_name.respond_to?(:valkyrie_class) ? model_name.valkyrie_class : model_name
23
+ end
24
+
25
+ def total_results(result_sets)
26
+ if result_sets.present?
27
+ total_result = result_sets.inject([]) do |out, set|
28
+ i = out.intersection(set)
29
+ out + (set - i)
30
+ end
31
+ total_result
32
+ else
33
+ result_sets
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def query_strategy_for_find_multiple(method_name, *args, **opts, &block)
40
+ # I don't know how we'll handle sums; as we're looking for counts of distinct items.
41
+ opts[:model] = setup_model(opts[:model]) if opts[:model]
42
+ result_sets = []
43
+ services.each do |service|
44
+ next unless service.respond_to?(method_name)
45
+ result = service.send(method_name, *args, **opts, &block)
46
+ result_sets << result.to_a if result.present? && result.respond_to?(:any?) && result.any?
47
+ rescue Valkyrie::Persistence::ObjectNotFoundError
48
+ next
49
+ end
50
+
51
+ # We need to remove items in both sets, but not remove duplicates with in the set because
52
+ # Valkyrie specifies that relationships can be duplicated (A can have [B, C, B, D] as
53
+ # children)
54
+ total_results(result_sets)
55
+ end
56
+
57
+ def query_strategy_for_count_multiple(method_name, *args, **opts, &block)
58
+ opts[:model] = setup_model(opts[:model]) if opts[:model]
59
+ result_sets = []
60
+ services.each do |service|
61
+ result = service.send(method_name, *args, **opts, &block)
62
+ result_sets << result if result.present?
63
+ rescue Valkyrie::Persistence::ObjectNotFoundError
64
+ next
65
+ end
66
+
67
+ result_sets.max
68
+ end
69
+
70
+ # @note we dont have a good way to remove items in both from the count since we dont want to
71
+ # load all of the items and de-dup them. There for we just return the highest number among the
72
+ # counts. This will be inaccurate if you start adding new items to the target repo while
73
+ # migrating
74
+ def query_strategy_for_find_single(method_name, *args, **opts, &block)
75
+ opts[:model] = setup_model(opts[:model]) if opts[:model]
76
+ result = nil
77
+ services.each do |service|
78
+ next unless service.respond_to?(method_name)
79
+ result = service.send(method_name, *args, **opts, &block)
80
+ return result if result.present?
81
+ rescue Valkyrie::Persistence::ObjectNotFoundError
82
+ next
83
+ end
84
+
85
+ return result unless result.nil?
86
+ raise Valkyrie::Persistence::ObjectNotFoundError
87
+ end
88
+
89
+ def query_strategy_for_find_single_or_nil(method_name, *args, **opts, &block)
90
+ query_strategy_for_find_single(method_name, *args, **opts, &block)
91
+ rescue Valkyrie::Persistence::ObjectNotFoundError
92
+ nil
93
+ end
94
+ end
95
+
96
+ extend ActiveSupport::Concern
97
+ included do
98
+ attr_reader :services
99
+ delegate :orm_class, to: :resource_factory
100
+
101
+ [:find_all,
102
+ :find_all_of_model,
103
+ :find_many_by_ids,
104
+ :find_members,
105
+ :find_references_by,
106
+ :find_inverse_references_by,
107
+ :find_inverse_references_by,
108
+ :find_parents].each do |method_name|
109
+ find_multiple(method_name)
110
+ end
111
+
112
+ [:find_by,
113
+ :find_by_alternate_identifier].each do |method_name|
114
+ find_single(method_name)
115
+ end
116
+
117
+ [:count_all_of_model].each do |method_name|
118
+ count_multiple(method_name)
119
+ end
120
+
121
+ include MethodMissingMachinations
122
+ end
123
+
124
+ class_methods do # rubocop:disable Metrics/BlockLength
125
+ def count_multiple(method_name)
126
+ # look in all services, combine and uniq results
127
+ define_method method_name do |*args, **opts, &block|
128
+ query_strategy_for_count_multiple(__method__, *args, **opts, &block)
129
+ end
130
+ end
131
+
132
+ def find_multiple(method_name)
133
+ # look in all services, combine and uniq results
134
+ define_method method_name do |*args, **opts, &block|
135
+ query_strategy_for_find_multiple(__method__, *args, **opts, &block)
136
+ end
137
+ end
138
+
139
+ def find_single(method_name)
140
+ define_method method_name do |*args, **opts, &block|
141
+ query_strategy_for_find_single(__method__, *args, **opts, &block)
142
+ end
143
+ end
144
+ end
145
+
146
+ # @param [QueryService] query_service
147
+ def initialize(*services)
148
+ @services = services
149
+ setup_custom_queries
150
+ end
151
+
152
+ # rubocop:disable Metrics/MethodLength
153
+ def setup_custom_queries
154
+ # load all the sql based custom queries
155
+ [
156
+ Hyrax::CustomQueries::Navigators::CollectionMembers,
157
+ Hyrax::CustomQueries::Navigators::ChildCollectionsNavigator,
158
+ Hyrax::CustomQueries::Navigators::ParentCollectionsNavigator,
159
+ Hyrax::CustomQueries::Navigators::ChildFileSetsNavigator,
160
+ Hyrax::CustomQueries::Navigators::ChildWorksNavigator,
161
+ Hyrax::CustomQueries::Navigators::FindFiles,
162
+ Hyrax::CustomQueries::FindAccessControl,
163
+ Hyrax::CustomQueries::FindCollectionsByType,
164
+ Hyrax::CustomQueries::FindFileMetadata,
165
+ Hyrax::CustomQueries::FindIdsByModel,
166
+ Hyrax::CustomQueries::FindManyByAlternateIds,
167
+ Hyrax::CustomQueries::FindModelsByAccess,
168
+ Hyrax::CustomQueries::FindCountBy,
169
+ Hyrax::CustomQueries::FindByDateRange
170
+ ].each do |handler|
171
+ services[0].custom_queries.register_query_handler(handler)
172
+ end
173
+ end
174
+ # rubocop:enable Metrics/MethodLength
175
+ end
176
+ end
@@ -118,6 +118,7 @@ module Hyrax
118
118
 
119
119
  # @!group Analytics
120
120
 
121
+ # This value determines whether to collect analytics or not
121
122
  attr_writer :analytics
122
123
  attr_reader :analytics
123
124
  def analytics?
@@ -125,6 +126,16 @@ module Hyrax
125
126
  ActiveModel::Type::Boolean.new.cast(ENV.fetch('HYRAX_ANALYTICS', false))
126
127
  end
127
128
 
129
+ # This value determines whether to show reports on the dashboard, work and collection report pages
130
+ # With Google: it's dependent on the GOOGLE_OAUTH_XXX values
131
+ # With Matomo: TODO
132
+ attr_writer :analytics_reporting
133
+ attr_reader :analytics_reporting
134
+ def analytics_reporting?
135
+ @analytics_reporting ||=
136
+ ActiveModel::Type::Boolean.new.cast(ENV.fetch('HYRAX_ANALYTICS_REPORTING', false))
137
+ end
138
+
128
139
  # Currently supports 'google' or 'matomo'
129
140
  # google is default for backward compatability
130
141
  attr_writer :analytics_provider
@@ -294,6 +305,14 @@ module Hyrax
294
305
  @fixity_service ||= Hyrax::Fixity::ActiveFedoraFixityService
295
306
  end
296
307
 
308
+ # This value determines whether to use load the Freyja adapter in dassie
309
+ attr_writer :valkyrie_transition
310
+ attr_reader :valkyrie_transition
311
+ def valkyrie_transition?
312
+ @valkyrie_transition ||=
313
+ ActiveModel::Type::Boolean.new.cast(ENV.fetch('VALKYRIE_TRANSITION', false))
314
+ end
315
+
297
316
  attr_writer :max_days_between_fixity_checks
298
317
  def max_days_between_fixity_checks
299
318
  @max_days_between_fixity_checks ||= 7
@@ -556,6 +575,22 @@ module Hyrax
556
575
  end
557
576
  attr_writer :disable_wings
558
577
 
578
+ ##
579
+ # @return [Boolean]
580
+ def disable_freyja
581
+ return @disable_freyja unless @disable_freyja.nil?
582
+ ActiveModel::Type::Boolean.new.cast(ENV.fetch('HYRAX_SKIP_FREYJA', false))
583
+ end
584
+ attr_writer :disable_freyja
585
+
586
+ ##
587
+ # @return [Boolean]
588
+ def disable_frigg
589
+ return @disable_frigg unless @disable_frigg.nil?
590
+ ActiveModel::Type::Boolean.new.cast(ENV.fetch('HYRAX_SKIP_FRIGG', false))
591
+ end
592
+ attr_writer :disable_frigg
593
+
559
594
  attr_writer :display_media_download_link
560
595
  # @return [Boolean]
561
596
  def display_media_download_link?
@@ -869,6 +904,21 @@ module Hyrax
869
904
  collection_model.safe_constantize
870
905
  end
871
906
 
907
+ ##
908
+ # @api private
909
+ #
910
+ # There are assumptions baked into {Wings} and tests regarding what the
911
+ # correct conceptual collection will be. This helps provide that connective
912
+ # tissue.
913
+ #
914
+ # It is definitely a hack to appease tests and the Double Combo/Goddess
915
+ # adapter migration.
916
+ def collection_class_for_wings
917
+ return collection_class if collection_class < Hyrax::Resource
918
+
919
+ Hyrax::PcdmCollection
920
+ end
921
+
872
922
  attr_writer :admin_set_model
873
923
  ##
874
924
  # @return [#constantize] a string representation of the admin set
@@ -883,6 +933,21 @@ module Hyrax
883
933
  admin_set_model.constantize
884
934
  end
885
935
 
936
+ ##
937
+ # @api private
938
+ #
939
+ # There are assumptions baked into {Wings} and tests regarding what the
940
+ # correct conceptual admin set will be. This helps provide that connective
941
+ # tissue.
942
+ #
943
+ # It is definitely a hack to appease tests and the Double Combo/Goddess
944
+ # adapter migration.
945
+ def admin_set_class_for_wings
946
+ return admin_set_class if admin_set_class < Hyrax::Resource
947
+
948
+ Hyrax::AdministrativeSet
949
+ end
950
+
886
951
  ##
887
952
  # @return [String] the default admin set id
888
953
  def default_admin_set_id
@@ -1089,6 +1154,24 @@ module Hyrax
1089
1154
  @visibility_map ||= Hyrax::VisibilityMap.instance
1090
1155
  end
1091
1156
 
1157
+ attr_writer :simple_schema_loader_config_search_paths
1158
+ # A configuration for modifying the SimpleSchemaLoader#config_search_paths
1159
+ # which will allow gems to add their own metadata yaml files and easily keep
1160
+ # them within the gem.
1161
+ #
1162
+ # @return [Array<Pathname>]
1163
+ # @see Hyrax::SimpleSchemaLoader#config_search_paths
1164
+ # @example
1165
+ # Hyrax.config do |config|
1166
+ # config.simple_schema_loader_config_search_paths.unshift(HykuKnapsack::Engine.root)
1167
+ # end
1168
+ #
1169
+ # Hyrax.config.simple_schema_loader_config_search_paths
1170
+ # => [#<Pathname:/app/samvera>, #<Pathname:/app/samvera/hyrax-webapp>, #<Pathname:/app/samvera/hyrax-webapp/gems/hyrax>]
1171
+ def simple_schema_loader_config_search_paths
1172
+ @simple_schema_loader_config_search_paths ||= [Rails.root, Hyrax::Engine.root]
1173
+ end
1174
+
1092
1175
  private
1093
1176
 
1094
1177
  # @param [Symbol, #to_s] model_name - symbol representing the model
data/lib/hyrax/engine.rb CHANGED
@@ -89,6 +89,8 @@ module Hyrax
89
89
 
90
90
  initializer 'requires' do
91
91
  require 'wings' unless Hyrax.config.disable_wings
92
+ require 'freyja' unless Hyrax.config.disable_freyja
93
+ require 'frigg' unless Hyrax.config.disable_frigg
92
94
  end
93
95
 
94
96
  initializer 'routing' do
@@ -46,12 +46,10 @@ module Hyrax
46
46
 
47
47
  def included(descendant)
48
48
  super
49
-
50
49
  form_field_definitions.each do |field_name, options|
51
- descendant.property field_name.to_sym, options.merge(display: true, default: [])
50
+ descendant.property field_name.to_sym, options.merge(display: options.fetch(:display, true), default: [])
52
51
  descendant.validates field_name.to_sym, presence: true if options.fetch(:required, false)
53
52
  end
54
-
55
53
  # Auto include any matching FormFieldBehaviors
56
54
  schema_name = name.to_s.camelcase
57
55
  behavior = "#{schema_name}FormFieldsBehavior".safe_constantize ||
data/lib/hyrax/name.rb CHANGED
@@ -17,5 +17,10 @@ module Hyrax
17
17
  @singular_route_key = ActiveSupport::Inflector.singularize(@route_key)
18
18
  @route_key += "_index" if @plural == @singular
19
19
  end
20
+
21
+ ##
22
+ # Expose the underlying klass which can be helpful when consider that we have the
23
+ # Hyrax::ValkyrieLazyMigration
24
+ attr_reader :klass
20
25
  end
21
26
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+
5
+ module Hyrax
6
+ module RuboCop
7
+ module CustomCops
8
+ # This custom cop checks for mixins of Hyrax::ArResource
9
+ class ArResource < ::RuboCop::Cop::Cop
10
+ MSG = 'Do not `include Hyrax::ArResource`.'
11
+
12
+ # checks for `include Hyrax::ArResource`
13
+ def_node_search :includes_hyrax_ar_resource?, <<-PATTERN
14
+ (send nil? {:include :extend} (const (const nil? :Hyrax) :ArResource))
15
+ PATTERN
16
+
17
+ # checks for `include ArResource`
18
+ def_node_search :includes_ar_resource?, <<-PATTERN
19
+ (send nil? {:include :extend} (const nil? :ArResource))
20
+ PATTERN
21
+
22
+ def on_send(send_node)
23
+ add_offense(send_node, message: MSG) if includes_hyrax_ar_resource?(send_node) || includes_ar_resource?(send_node)
24
+ end
25
+ end
26
+
27
+ # class AdditionalCustomCops < ::RuboCop::Cop::Cop; end
28
+ end
29
+ end
30
+ end
@@ -19,13 +19,13 @@ require 'selenium-webdriver'
19
19
  Capybara.save_path = ENV['CI'] ? "/tmp/test-results" : Rails.root.join('tmp', 'capybara')
20
20
 
21
21
  options = Selenium::WebDriver::Chrome::Options.new.tap do |opts|
22
- opts.add_argument("--headless") if ENV["CHROME_HEADLESS_MODE"]
22
+ opts.add_argument("--headless=new") if ENV["CHROME_HEADLESS_MODE"]
23
+ # opts.add_argument("--no-sandbox")
24
+ # opts.add_argument("--disable-dev-shm-usage")
23
25
  opts.add_argument("--disable-gpu") if Gem.win_platform?
24
- # Workaround https://bugs.chromium.org/p/chromedriver/issues/detail?id=2650&q=load&sort=-id&colspec=ID%20Status%20Pri%20Owner%20Summary
25
- opts.add_argument("--disable-site-isolation-trials")
26
26
  opts.add_argument("--window-size=1440,1440")
27
- opts.add_argument("--enable-features=NetworkService,NetworkServiceInProcess")
28
- opts.add_argument("--disable-features=VizDisplayCompositor")
27
+ # opts.add_argument("--enable-features=NetworkService,NetworkServiceInProcess")
28
+ # opts.add_argument("--disable-features=VizDisplayCompositor")
29
29
  end
30
30
 
31
31
  Capybara.register_driver :selenium_chrome_headless_sandboxless do |app|
@@ -46,7 +46,8 @@ end
46
46
  Capybara.server_host = '0.0.0.0'
47
47
  Capybara.server_port = 3010
48
48
 
49
- ip = IPSocket.getaddress(Socket.gethostname)
49
+ # ip = IPSocket.getaddress(Socket.gethostname)
50
+ ip = `hostname -s`.strip
50
51
  Capybara.app_host = "http://#{ip}:#{Capybara.server_port}"
51
52
 
52
53
  Capybara.default_driver = :rack_test # This is a faster driver
@@ -87,5 +88,8 @@ end
87
88
  RSpec.configure do |config|
88
89
  config.after(:each, :js) do |example|
89
90
  save_timestamped_page_and_screenshot(Capybara.page, example.metadata) if example.exception
91
+ # Quitting forces the browser session to be reinitialized during the next :js spec.
92
+ # This is slower but more resilient to timeouts (in theory).
93
+ Capybara.page.driver.quit
90
94
  end
91
95
  end
@@ -11,6 +11,7 @@ FactoryBot.define do
11
11
  after(:create) do |admin_set, evaluator|
12
12
  if evaluator.with_permission_template
13
13
  attributes = { source_id: admin_set.id }
14
+ attributes = evaluator.permission_template_attributes.merge(attributes) if evaluator.permission_template_attributes.respond_to?(:merge)
14
15
  attributes = evaluator.with_permission_template.merge(attributes) if evaluator.with_permission_template.respond_to?(:merge)
15
16
  # There is a unique constraint on permission_templates.source_id; I don't want to
16
17
  # create a permission template if one already exists for this admin_set
@@ -21,6 +22,7 @@ FactoryBot.define do
21
22
  transient do
22
23
  # false, true, or Hash with keys for permission_template
23
24
  with_permission_template { false }
25
+ permission_template_attributes { {} }
24
26
  end
25
27
 
26
28
  factory :complete_admin_set do
@@ -5,6 +5,10 @@ FactoryBot.define do
5
5
  visibility_after_embargo { 'open' }
6
6
  visibility_during_embargo { 'authenticated' }
7
7
 
8
+ after(:build) do |embargo, evaluator|
9
+ embargo.embargo_release_date = evaluator.embargo_release_date.to_datetime
10
+ end
11
+
8
12
  to_create do |instance|
9
13
  saved_instance = Valkyrie.config.metadata_adapter.persister.save(resource: instance)
10
14
  instance.id = saved_instance.id
@@ -5,6 +5,10 @@ FactoryBot.define do
5
5
  visibility_after_lease { 'authenticated' }
6
6
  visibility_during_lease { 'open' }
7
7
 
8
+ after(:build) do |lease, evaluator|
9
+ lease.lease_expiration_date = evaluator.lease_expiration_date.to_datetime
10
+ end
11
+
8
12
  to_create do |instance|
9
13
  saved_instance = Valkyrie.config.metadata_adapter.persister.save(resource: instance)
10
14
  instance.id = saved_instance.id
@@ -87,8 +87,15 @@ FactoryBot.define do
87
87
  end
88
88
 
89
89
  if evaluator.respond_to?(:admin_set) && evaluator.admin_set.present?
90
+ # We're likely going to want to apply permissions
90
91
  template = Hyrax::PermissionTemplate.find_by(source_id: evaluator.admin_set.id)
91
- Hyrax::PermissionTemplateApplicator.apply(template).to(model: work) if template
92
+ if template
93
+ Hyrax::PermissionTemplateApplicator.apply(template).to(model: work)
94
+ if template.active_workflow.present?
95
+ user = User.find_by(Hydra.config.user_key_field => work.depositor)
96
+ Hyrax::Workflow::WorkflowFactory.create(work, {}, user)
97
+ end
98
+ end
92
99
  end
93
100
 
94
101
  work.permission_manager.edit_groups = work.permission_manager.edit_groups.to_a + evaluator.edit_groups
@@ -100,7 +107,14 @@ FactoryBot.define do
100
107
  Hyrax::EmbargoManager.new(resource: work).apply
101
108
  Hyrax::LeaseManager.new(resource: work).apply
102
109
 
103
- work.permission_manager.acl.save
110
+ if evaluator.with_index
111
+ work.permission_manager.acl.save
112
+ else
113
+ # manually save acl change_set so it does not automatically index the work
114
+ change_set = work.permission_manager.acl.send(:change_set)
115
+ change_set.sync
116
+ Hyrax.persister.save(resource: change_set.resource)
117
+ end
104
118
 
105
119
  # This has to happen after permissions for permissions to propagate.
106
120
  if evaluator.uploaded_files.present?
@@ -374,7 +374,7 @@ RSpec.shared_examples 'a Hyrax::FileSet', valkyrie_adapter: :test_adapter do
374
374
  end
375
375
 
376
376
  context 'with simulated original file' do
377
- let(:file_metadata_double) { double("Fake Hyrax::FileMetadata", id: SecureRandom.uuid, file_identifier: SecureRandom.uuid, versions: [file_double]) }
377
+ let(:file_metadata_double) { double("Fake Hyrax::FileMetadata", id: SecureRandom.uuid, file_identifier: "versiondisk://#{Rails.root.join / 'tmp' / 'test_adapter_uploads'}/#{SecureRandom.uuid}", versions: [file_double]) }
378
378
  let(:file_double) { double("Fake Valkyrie::StorageAdapter::File", id: SecureRandom.uuid, version_id: SecureRandom.uuid)}
379
379
 
380
380
  before do
@@ -11,7 +11,8 @@ module Hyrax
11
11
  DEFAULT_STEPS = ['admin_set_resource.check_default',
12
12
  'admin_set_resource.check_empty',
13
13
  'admin_set_resource.delete',
14
- 'admin_set_resource.delete_acl'].freeze
14
+ 'admin_set_resource.delete_acl',
15
+ 'admin_set_resource.delete_permission_template'].freeze
15
16
 
16
17
  ##
17
18
  # @see Hyrax::Transactions::Transaction
@@ -11,7 +11,8 @@ module Hyrax
11
11
  # TODO: Add step that checks if collection is empty for collections of types that require it
12
12
  DEFAULT_STEPS = ['collection_resource.delete_acl',
13
13
  'collection_resource.remove_from_membership',
14
- 'collection_resource.delete'].freeze
14
+ 'collection_resource.delete',
15
+ 'collection_resource.delete_permission_template'].freeze.freeze
15
16
 
16
17
  ##
17
18
  # @see Hyrax::Transactions::Transaction
@@ -42,6 +42,7 @@ module Hyrax
42
42
  require 'hyrax/transactions/steps/delete_access_control'
43
43
  require 'hyrax/transactions/steps/delete_all_file_metadata'
44
44
  require 'hyrax/transactions/steps/delete_all_file_sets'
45
+ require 'hyrax/transactions/steps/delete_permission_template'
45
46
  require 'hyrax/transactions/steps/delete_resource'
46
47
  require 'hyrax/transactions/steps/ensure_admin_set'
47
48
  require 'hyrax/transactions/steps/file_metadata_delete'
@@ -202,6 +203,10 @@ module Hyrax
202
203
  ops.register 'save_acl' do
203
204
  Steps::SaveAccessControl.new
204
205
  end
206
+
207
+ ops.register 'delete_permission_template' do
208
+ Steps::DeletePermissionTemplate.new
209
+ end
205
210
  end
206
211
 
207
212
  namespace 'collection_resource' do |ops| # Hyrax::PcdmCollection resource
@@ -229,6 +234,10 @@ module Hyrax
229
234
  Steps::SaveAccessControl.new
230
235
  end
231
236
 
237
+ ops.register 'delete_permission_template' do
238
+ Steps::DeletePermissionTemplate.new
239
+ end
240
+
232
241
  ops.register 'save_collection_banner' do
233
242
  Steps::SaveCollectionBanner.new
234
243
  end
@@ -27,8 +27,9 @@ module Hyrax
27
27
  if @handler.new(work: obj).add(files: uploaded_files, file_set_params: file_set_params).attach
28
28
  file_sets = obj.member_ids.map do |member|
29
29
  Hyrax.query_service.find_by(id: member) if Hyrax.query_service.find_by(id: member).is_a? Hyrax::FileSet
30
- end
30
+ end.compact
31
31
 
32
+ # TODO: improve queries - Non performant to perform single queries. Perhapds queries ids then reject.
32
33
  Hyrax::LeaseManager.create_or_update_lease_on_members(file_sets, obj) if obj.lease
33
34
  Hyrax::EmbargoManager.create_or_update_embargo_on_members(file_sets, obj) if obj.embargo
34
35
  Success(obj)
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ require 'dry/monads'
3
+
4
+ module Hyrax
5
+ module Transactions
6
+ module Steps
7
+ ##
8
+ # Deletes the Hyrax::PermissionTemplate for a resource.
9
+ # If no PermissionTemplate associated with that resource is found, succeeds.
10
+ #
11
+ # @see https://dry-rb.org/gems/dry-monads/1.0/result/
12
+ class DeletePermissionTemplate
13
+ include Dry::Monads[:result]
14
+
15
+ ##
16
+ # @param [Valkyrie::Resource] obj
17
+ #
18
+ # @return [Dry::Monads::Result]
19
+ def call(obj)
20
+ permission_template = Hyrax::PermissionTemplate.find_by(source_id: obj.id)
21
+ return Success(obj) if permission_template.nil?
22
+
23
+ permission_template.destroy || (return Failure[:failed_to_delete_permission_template, permission_template])
24
+
25
+ Success(obj)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -27,8 +27,8 @@ module Hyrax
27
27
  def call(resource, user: nil)
28
28
  return Failure(:resource_not_persisted) unless resource.persisted?
29
29
 
30
- @persister.delete(resource: resource)
31
30
  publish_changes(resource: resource, user: user)
31
+ @persister.delete(resource: resource)
32
32
 
33
33
  Success(resource)
34
34
  end
@@ -19,7 +19,8 @@ module Hyrax
19
19
  #
20
20
  # @return [Dry::Monads::Result] `Failure` if the work fails to save;
21
21
  # `Success(input)`, otherwise.
22
- def call(collection_resource, update_logo_file_ids: nil, alttext_values: nil, linkurl_values: nil)
22
+ def call(collection_resource, update_logo_file_ids: nil, alttext_values: nil, linkurl_values: nil, logo_unchanged_indicator: true)
23
+ return Success(collection_resource) if ActiveModel::Type::Boolean.new.cast(logo_unchanged_indicator)
23
24
  collection_id = collection_resource.id.to_s
24
25
  process_logo_input(collection_id: collection_id, update_logo_file_ids: update_logo_file_ids, alttext_values: alttext_values, linkurl_values: linkurl_values)
25
26
  Success(collection_resource)
@@ -19,10 +19,17 @@ module Hyrax
19
19
  #
20
20
  # @raise Hyrax::ObjectNotFoundError
21
21
  def self.find(_model_class, id)
22
- return Hyrax.query_service.find_by(id: id) unless Hyrax.config.enable_noids?
22
+ self.find_by(id:) ||
23
23
  Hyrax.query_service.find_by_alternate_identifier(alternate_identifier: id)
24
24
  rescue Valkyrie::Persistence::ObjectNotFoundError => err
25
25
  raise Hyrax::ObjectNotFoundError, err.message
26
26
  end
27
+
28
+ private
29
+
30
+ def self.find_by(id:)
31
+ Hyrax.query_service.find_by(id:)
32
+ rescue Valkyrie::Persistence::ObjectNotFoundError
33
+ end
27
34
  end
28
35
  end
data/lib/hyrax/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Hyrax
3
- VERSION = '5.0.1'
3
+ VERSION = '5.0.3'
4
4
  end
@@ -143,18 +143,26 @@ module Wings
143
143
  end
144
144
  # rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength
145
145
 
146
+ # rubocop:disable Metrics/AbcSize
146
147
  def parse_attributes(af_object)
147
148
  converted_attrs = normal_attributes
148
- members = Array.wrap(converted_attrs.delete(:members))
149
- files = converted_attrs.delete(:files)
150
- af_object.attributes = converted_attrs
149
+ af_object.attributes = converted_attrs.except(:members, :files, :file_name)
150
+ af_object.original_filename = converted_attrs[:file_name] if converted_attrs[:file_name]
151
151
  af_object.extracted_text = create_extrated_text(af_object) if resource.attributes[:extracted_text_id].present?
152
152
  perform_lease_conversion(af_object: af_object, resource: resource)
153
153
  perform_embargo_conversion(af_object: af_object, resource: resource)
154
- members.empty? ? af_object.try(:ordered_members)&.clear : af_object.try(:ordered_members=, members)
155
- af_object.try(:members)&.replace(members)
154
+
155
+ if converted_attrs.keys.include?(:members)
156
+ members = Array.wrap(converted_attrs.delete(:members))
157
+ members.empty? ? af_object.try(:ordered_members)&.clear : af_object.try(:ordered_members=, members)
158
+ af_object.try(:members)&.replace(members)
159
+ end
160
+
161
+ return unless converted_attrs.keys.include?(:files)
162
+ files = converted_attrs.delete(:files)
156
163
  af_object.files.build_or_set(files) if files
157
164
  end
165
+ # rubocop:enable Metrics/AbcSize
158
166
 
159
167
  def create_extrated_text(af_object)
160
168
  pcdm_et_file = af_object.extracted_text.presence || af_object.create_extracted_text