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
@@ -11,15 +11,38 @@ module Hyrax
11
11
  :original_file
12
12
  end
13
13
 
14
+ # We want to alias the show method for a later use with #show_active_fedora;
15
+ # because we're adding quite a bit of logic and need a good alias. Why the
16
+ # alias? Because we were using `super' for the show method and that just
17
+ # doesn't quite work with all of the antics we're performing.
18
+ alias hydra_show_active_fedora_file show
19
+
14
20
  # Render the 404 page if the file doesn't exist.
15
21
  # Otherwise renders the file.
16
22
  def show
23
+ # We will use the thumbnail from our file system first, if one exists
24
+ # Otherwise we will fallback to Valkyrie, then the default implementations
25
+ use = params.fetch(:file, :original_file).to_sym
26
+ if use == :thumbnail
27
+ thumbnail = Hyrax::DerivativePath.derivative_path_for_reference(params[:id], 'thumbnail')
28
+ if thumbnail.present? && File.exist?(thumbnail)
29
+ @file = thumbnail
30
+ return send_local_content
31
+ end
32
+ end
33
+
17
34
  return show_valkyrie if Hyrax.config.use_valkyrie?
18
35
 
36
+ show_active_fedora
37
+ end
38
+
39
+ private
40
+
41
+ def show_active_fedora
19
42
  case file
20
43
  when ActiveFedora::File
21
44
  # For original files that are stored in fedora
22
- super
45
+ hydra_show_active_fedora_file
23
46
  when String
24
47
  # For derivatives stored on the local file system
25
48
  send_local_content
@@ -28,8 +51,6 @@ module Hyrax
28
51
  end
29
52
  end
30
53
 
31
- private
32
-
33
54
  # Override the Hydra::Controller::DownloadBehavior#content_options so that
34
55
  # we have an attachement rather than 'inline'
35
56
  def content_options
@@ -8,7 +8,7 @@ module Hyrax
8
8
  include Hyrax::Breadcrumbs
9
9
 
10
10
  before_action :authenticate_user!, except: [:show, :citation, :stats]
11
- load_and_authorize_resource class: ::FileSet, except: :show
11
+ load_and_authorize_resource class: Hyrax.config.file_set_class
12
12
  before_action :build_breadcrumbs, only: [:show, :edit, :stats]
13
13
  before_action do
14
14
  blacklight_config.track_search_session = false
@@ -94,7 +94,7 @@ module Hyrax
94
94
  # @api public
95
95
  def delete(file_set:)
96
96
  case file_set
97
- when Valkyrie::Resource
97
+ when Hyrax::Resource
98
98
  transactions['file_set.destroy']
99
99
  .with_step_args('file_set.remove_from_work' => { user: current_user },
100
100
  'file_set.delete' => { user: current_user })
@@ -123,20 +123,46 @@ module Hyrax
123
123
  def valkyrie_update_metadata
124
124
  change_set = Hyrax::Forms::ResourceForm.for(resource: file_set)
125
125
 
126
+ attributes = coerce_valkyrie_params
127
+
128
+ # TODO: We are not performing any error checks. So that's something to
129
+ # correct.
126
130
  result =
127
131
  change_set.validate(attributes) &&
128
132
  transactions['change_set.update_file_set']
129
133
  .with_step_args(
130
- 'file_set.save_acl' => { permissions_params: change_set.input_params["permissions"] }
131
- )
134
+ 'file_set.save_acl' => { permissions_params: change_set.input_params["permissions"] }
135
+ )
132
136
  .call(change_set).value_or { false }
133
137
  @file_set = result if result
134
138
  end
135
139
 
140
+ def coerce_valkyrie_params
141
+ attrs = attributes
142
+ # The HTML form might not submit the required data structure for reform;
143
+ # namely instead of a hash with positional arguments for nested attributes
144
+ # of a collection, it is an array. So we conditionally coerce that Array
145
+ # to a Hash.
146
+
147
+ # TODO: Do we need to concern ourself with embargo_attributes and
148
+ # lease_attributes? My suspicion is that since these are singular (for
149
+ # now), we don't. But it's a quick add.
150
+ [:permissions].each do |name|
151
+ next unless attrs["#{name}_attributes"].is_a?(Array)
152
+ new_perm_attrs = {}
153
+ attrs["#{name}_attributes"].each_with_index do |el, i|
154
+ new_perm_attrs[i] = el
155
+ end
156
+
157
+ attrs["#{name}_attributes"] = new_perm_attrs
158
+ end
159
+ attrs
160
+ end
161
+
136
162
  def parent(file_set: curation_concern)
137
163
  @parent ||=
138
164
  case file_set
139
- when Hyrax::FileSet
165
+ when Hyrax::Resource
140
166
  # TODO: Add Hyrax::FileSet#parent method
141
167
  Hyrax.query_service.find_parents(resource: file_set).first
142
168
  else
@@ -145,7 +171,7 @@ module Hyrax
145
171
  end
146
172
 
147
173
  def attempt_update
148
- return attempt_update_valkyrie if ::FileSet < Hyrax::Resource
174
+ return attempt_update_valkyrie if curation_concern.is_a?(Hyrax::Resource)
149
175
  if wants_to_revert?
150
176
  actor.revert_content(params[:revision])
151
177
  elsif params.key?(:file_set)
@@ -24,6 +24,7 @@ module Hyrax
24
24
  add_breadcrumb t(:'hyrax.admin.sidebar.works'), hyrax.my_works_path
25
25
  managed_works_count
26
26
  @create_work_presenter = create_work_presenter_class.new(current_user)
27
+ @admin_sets_for_select = admin_sets_for_select
27
28
  super
28
29
  end
29
30
 
@@ -47,6 +48,25 @@ module Hyrax
47
48
  def managed_works_count
48
49
  @managed_works_count = Hyrax::Works::ManagedWorksService.managed_works_count(scope: self)
49
50
  end
51
+
52
+ def admin_sets_for_select
53
+ source_ids = Hyrax::Collections::PermissionsService.source_ids_for_deposit(ability: current_ability, source_type: 'admin_set')
54
+
55
+ admin_sets_list = Hyrax.query_service.find_many_by_ids(ids: source_ids).map do |source|
56
+ [source.title.first, source.id]
57
+ end
58
+
59
+ # Sorts the default admin set to be first, then the rest by title.
60
+ admin_sets_list.sort do |a, b|
61
+ if Hyrax::AdminSetCreateService.default_admin_set?(id: a[1])
62
+ -1
63
+ elsif Hyrax::AdminSetCreateService.default_admin_set?(id: b[1])
64
+ 1
65
+ else
66
+ a[0] <=> b[0]
67
+ end
68
+ end
69
+ end
50
70
  end
51
71
  end
52
72
  end
@@ -27,7 +27,7 @@ module Hyrax
27
27
  when 'file'
28
28
  add_breadcrumb I18n.t("hyrax.file_set.browse_view"), main_app.hyrax_file_set_path(params["id"])
29
29
  when 'work'
30
- add_breadcrumb @work.to_s, main_app.polymorphic_path(@work)
30
+ add_breadcrumb @work.title.first, main_app.polymorphic_path(@work)
31
31
  end
32
32
  end
33
33
  end
@@ -4,8 +4,12 @@ module Hyrax
4
4
  load_and_authorize_resource class: Hyrax::UploadedFile
5
5
 
6
6
  def create
7
- @upload.attributes = { file: params[:files].first,
8
- user: current_user }
7
+ if params[:id].blank?
8
+ @upload.attributes = { file: params[:files].first,
9
+ user: current_user }
10
+ else
11
+ upload_with_chunking
12
+ end
9
13
  @upload.save!
10
14
  end
11
15
 
@@ -13,5 +17,27 @@ module Hyrax
13
17
  @upload.destroy
14
18
  head :no_content
15
19
  end
20
+
21
+ private
22
+
23
+ def upload_with_chunking
24
+ @upload = Hyrax::UploadedFile.find(params[:id])
25
+ unpersisted_upload = Hyrax::UploadedFile.new(file: params[:files].first, user: current_user)
26
+
27
+ # Check if CONTENT-RANGE header is present
28
+ content_range = request.headers['CONTENT-RANGE']
29
+ return @upload.file = unpersisted_upload.file if content_range.nil?
30
+
31
+ # deal with chunks
32
+ current_size = @upload.file.size
33
+ begin_of_chunk = content_range[/\ (.*?)-/, 1].to_i # "bytes 100-999999/1973660678" will return '100'
34
+
35
+ # Add the following chunk to the incomplete upload
36
+ if @upload.file.present? && begin_of_chunk == current_size
37
+ File.open(@upload.file.path, "ab") { |f| f.write(params[:files].first.read) }
38
+ else
39
+ @upload.file = unpersisted_upload.file
40
+ end
41
+ end
16
42
  end
17
43
  end
@@ -47,7 +47,7 @@ module Hyrax
47
47
 
48
48
  # The color links
49
49
  def link_color
50
- block_for('link_color', '#2e74b2')
50
+ block_for('link_color', '#104C75')
51
51
  end
52
52
 
53
53
  # The color for links in the footer
@@ -10,7 +10,7 @@ module Hyrax
10
10
  delegate :title, :description, :brandable, :discoverable, :nestable, :sharable, :share_applies_to_new_works,
11
11
  :require_membership, :allow_multiple_membership, :assigns_workflow,
12
12
  :assigns_visibility, :id, :collection_type_participants, :persisted?,
13
- :admin_set?, :user_collection?, :badge_color, to: :collection_type
13
+ :admin_set?, :user_collection?, :badge_color, :collections?, to: :collection_type
14
14
 
15
15
  ##
16
16
  # @return [Boolean]
@@ -23,12 +23,6 @@ module Hyrax
23
23
  def share_options_disabled?
24
24
  all_settings_disabled? || !sharable
25
25
  end
26
-
27
- ##
28
- # @return [Boolean]
29
- def collections?
30
- collection_type.collections.any?
31
- end
32
26
  end
33
27
  end
34
28
  end
@@ -81,6 +81,15 @@ module Hyrax
81
81
  secondary_terms.any?
82
82
  end
83
83
 
84
+ ##
85
+ # This feature is not supported in Valkyrie collections and should be removed as part of #5764
86
+ # However, the depreciated method is still needed for some specs
87
+ # @return [] always empty.
88
+ def select_files
89
+ Deprecation.warn "`Hyrax::PcdmCollection` does not currently support thumbnail_id. Collection thumbnails need to be redesigned as part of issue #5764"
90
+ []
91
+ end
92
+
84
93
  private
85
94
 
86
95
  def _form_field_definitions
@@ -31,6 +31,12 @@ module Hyrax
31
31
  def model_name
32
32
  model.to_model.model_name
33
33
  end
34
+
35
+ ##
36
+ # @return [String]
37
+ def to_s
38
+ [*model.title].join(' ')
39
+ end
34
40
  end
35
41
  end
36
42
  end
@@ -31,6 +31,12 @@ module Hyrax
31
31
  def model_name
32
32
  model.to_model.model_name
33
33
  end
34
+
35
+ ##
36
+ # @return [String]
37
+ def to_s
38
+ [*model.title].join(' ')
39
+ end
34
40
  end
35
41
  end
36
42
  end
@@ -6,7 +6,7 @@ module Hyrax
6
6
  module LocationIndexer
7
7
  def to_solr
8
8
  super.tap do |index_document|
9
- index_document[:based_near_label_tesim] = based_near_label_lookup(resource.based_near) if resource.respond_to? :based_near
9
+ index_document[:based_near_label_tesim] = index_document[:based_near_label_sim] = based_near_label_lookup(resource.based_near) if resource.respond_to? :based_near
10
10
  end
11
11
  end
12
12
 
@@ -14,7 +14,7 @@ module Hyrax
14
14
 
15
15
  def based_near_label_lookup(locations)
16
16
  locations.map do |loc|
17
- location_service.full_label(loc)
17
+ location_service.full_label(loc) if loc.present?
18
18
  end
19
19
  end
20
20
 
@@ -101,6 +101,10 @@ module Hyrax
101
101
 
102
102
  # attributes set by fits for video
103
103
  solr_doc['aspect_ratio_tesim'] = file_metadata.aspect_ratio if file_metadata.aspect_ratio.present?
104
+
105
+ # support for derivatives download
106
+ derivatives = resource.extensions_and_mime_types
107
+ solr_doc['extensions_and_mime_types_ssm'] = derivatives.to_json if derivatives.present?
104
108
  end
105
109
  end
106
110
 
@@ -47,6 +47,7 @@ module Hyrax
47
47
  "system_modified_dtsi": resource.updated_at,
48
48
  "has_model_ssim": resource.to_rdf_representation,
49
49
  "human_readable_type_tesim": resource.human_readable_type,
50
+ "human_readable_type_sim": resource.human_readable_type,
50
51
  "alternate_ids_sim": resource.alternate_ids.map(&:to_s)
51
52
  }.with_indifferent_access
52
53
  end
@@ -9,11 +9,9 @@ module Hyrax
9
9
  super
10
10
  end
11
11
 
12
- class << self
13
- def for(*args, **kwargs)
14
- Deprecation.warn "`Hyrax::ValkyrieIndexer.for` is deprecated. Use `Hyrax::Indexers::ResourceIndexer.for` instead."
15
- Hyrax::Indexers::ResourceIndexer.for(*args, **kwargs)
16
- end
12
+ def self.for(*args, **kwargs)
13
+ Deprecation.warn "`Hyrax::ValkyrieIndexer.for` is deprecated. Use `Hyrax::Indexers::ResourceIndexer.for` instead."
14
+ Hyrax::Indexers::ResourceIndexer.for(*args, **kwargs)
17
15
  end
18
16
  end
19
17
  end
@@ -0,0 +1,109 @@
1
+ ##
2
+ # Responsible for conditionally enqueuing the file and thumbnail migration
3
+ # logic of an ActiveFedora object.
4
+ class MigrateFilesToValkyrieJob < Hyrax::ApplicationJob
5
+ ##
6
+ #
7
+ # @param resource [Hyrax::FileSet]
8
+ def perform(resource)
9
+ migrate_derivatives!(resource:)
10
+ # need to reload file_set to get the derivative ids
11
+ resource = Hyrax.query_service.find_by(id: resource.id)
12
+ migrate_files!(resource: resource)
13
+ end
14
+
15
+ def attribute_mapping
16
+ return @attribute_mapping if @attribute_mapping
17
+ @attribute_mapping = %w[
18
+ aspect_ratio bit_depth bit_rate byte_order capture_device channels character_count character_set
19
+ checksum color_map color_space compression creator data_format duration exif_version file_title
20
+ fits_version format_label frame_rate gps_timestamp graphics_count height image_producer language
21
+ latitude line_count longitude markup_basis markup_language offset orientation page_count
22
+ paragraph_count profile_name profile_version recorded_size sample_rate scanning_software
23
+ table_count well_formed width word_count ].inject({}) { |j, i| j[i] = i; j}
24
+ @attribute_mapping['recorded_size'] = 'file_size'
25
+ @attribute_mapping['channels'] = 'alpha_channels'
26
+ @attribute_mapping['checksum'] = 'original_checksum'
27
+ @attribute_mapping
28
+ end
29
+
30
+ private
31
+
32
+ def migrate_derivatives!(resource:)
33
+ # @todo should we trigger a job if the member is a child work?
34
+ paths = Hyrax::DerivativePath.derivatives_for_reference(resource)
35
+ paths.each do |path|
36
+ container = container_for(path)
37
+ mime_type = Marcel::MimeType.for(extension: File.extname(path))
38
+ directives = { url: path, container: container, mime_type: mime_type }
39
+ File.open(path, 'rb') do |content|
40
+ Hyrax::ValkyriePersistDerivatives.call(content, directives)
41
+ end
42
+ end
43
+ end
44
+
45
+ ##
46
+ # Move the ActiveFedora files out of ActiveFedora's domain and into the
47
+ # configured {Hyrax.storage_adapter}'s domain.
48
+ def migrate_files!(resource:)
49
+ return unless resource.respond_to?(:file_ids)
50
+
51
+ files = Hyrax.custom_queries.find_many_file_metadata_by_ids(ids: resource.file_ids)
52
+ files.each do |file|
53
+ # If it doesn't start with fedora, we've likely already migrated it.
54
+ next unless /^fedora:/.match?(file.file_identifier.to_s)
55
+ resource.file_ids.delete(file.id)
56
+
57
+ Tempfile.create do |tempfile|
58
+ tempfile.binmode
59
+ tempfile.write(URI.open(file.file_identifier.to_s.gsub("fedora:", "http:")).read)
60
+ tempfile.rewind
61
+
62
+ # valkyrie_file = Hyrax.storage_adapter.upload(resource: resource, file: tempfile, original_filename: file.original_filename)
63
+ valkyrie_file = Hyrax::ValkyrieUpload.file(
64
+ filename: resource.label,
65
+ file_set: resource,
66
+ io: tempfile,
67
+ use: file.pcdm_use.select {|use| Hyrax::FileMetadata::Use.use_list.include?(use)},
68
+ user: User.find_or_initialize_by(User.user_key_field => resource.depositor),
69
+ mime_type: file.mime_type,
70
+ skip_derivatives: true
71
+ )
72
+ valkyrie_file = copy_attributes(valkyrie_file:, original_file: file)
73
+ Hyrax.persister.save(resource: valkyrie_file)
74
+ end
75
+ end
76
+ # reindex the file set after migrating files to include characterization info
77
+ Hyrax.index_adapter.save(resource: resource)
78
+ end
79
+
80
+ def copy_attributes(valkyrie_file:, original_file:)
81
+ attribute_mapping.each do |k, v|
82
+ valkyrie_file.set_value(k, original_file.send(v))
83
+ end
84
+ # Special case as this property isn't in the characterization proxy
85
+ valkyrie_file.set_value('alternate_ids', original_file.alternate_ids)
86
+ valkyrie_file
87
+ end
88
+
89
+ ##
90
+ # Map from the file name used for the derivative to a valid option for
91
+ # container that ValkyriePersistDerivatives can convert into a
92
+ # Hyrax::Metadata::Use
93
+ #
94
+ # @param filename [String] the name of the derivative file: i.e. 'x-thumbnail.jpg'
95
+ # @return [String]
96
+ def container_for(filename)
97
+ # we want the portion between the '-' and the '.'
98
+ file_blob = File.basename(filename, '.*').split('-').last
99
+
100
+ case file_blob
101
+ when 'thumbnail'
102
+ 'thumbnail_image'
103
+ when 'txt', 'json', 'xml'
104
+ 'extracted_text'
105
+ else
106
+ 'service_file'
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ # migrates models from AF to valkyrie
4
+ class MigrateResourcesJob < ApplicationJob
5
+ attr_writer :errors
6
+ # input [Array>>String] Array of ActiveFedora model names to migrate to valkyrie objects
7
+ # defaults to AdminSet & Collection models if empty
8
+ def perform(ids: [], models: ['AdminSet', 'Collection'])
9
+ if ids.blank?
10
+ models.each do |model|
11
+ model.constantize.find_each do |item|
12
+ migrate(item.id)
13
+ end
14
+ end
15
+ else
16
+ ids.each do |id|
17
+ migrate(id)
18
+ end
19
+ end
20
+ raise errors.inspect if errors.present?
21
+ end
22
+
23
+ def errors
24
+ @errors ||= []
25
+ end
26
+
27
+ def migrate(id)
28
+ resource = Hyrax.query_service.find_by(id: id)
29
+ return unless resource.wings? # this resource has already been converted
30
+ result = MigrateResourceService.new(resource: resource).call
31
+ errors << result unless result.success?
32
+ result
33
+ end
34
+ end
@@ -16,8 +16,9 @@ class ValkyrieCreateDerivativesJob < Hyrax::ApplicationJob
16
16
 
17
17
  def reindex_parent(file_set_id)
18
18
  file_set = Hyrax.query_service.find_by(id: file_set_id)
19
+ return unless file_set
19
20
  parent = Hyrax.custom_queries.find_parent_work(resource: file_set)
20
- return unless parent.thumbnail_id == file_set.id
21
+ return unless parent&.thumbnail_id == file_set.id
21
22
  Hyrax.logger.debug { "Reindexing #{parent.id} due to creation of thumbnail derivatives." }
22
23
  Hyrax.index_adapter.save(resource: parent)
23
24
  end
@@ -17,6 +17,7 @@
17
17
  # @see Hyrax::DefaultAdminSetActor
18
18
  # @see Hyrax::ApplyPermissionTemplateActor
19
19
  class AdminSet < ActiveFedora::Base
20
+ include Hydra::PCDM::CollectionBehavior
20
21
  include Hydra::AccessControls::Permissions
21
22
  include Hyrax::Noid
22
23
  include Hyrax::HumanReadableType
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+ module Hyrax
3
+ # An optional model to bring active record like accessors to your Valkyrie resources. This
4
+ # is simply for simplicity in the console and backward compatibility.
5
+ module ArResource
6
+ extend ActiveSupport::Concern
7
+
8
+ class_methods do
9
+ ##
10
+ # find a Valkyrie object by its primary identifyer.
11
+ #
12
+ # @param id [String]
13
+ # @return [Valkyrie::Resource]
14
+ def find(id, query_service: Hyrax.query_service)
15
+ query_service.find_by(id: id)
16
+ end
17
+
18
+ ##
19
+ # find and item by an arbitrary keyword arguements if and only if that property is supported
20
+ # by the current query_service. custom queries are often limited so be aware that this does
21
+ # support all properties of an object.
22
+ #
23
+ # @params query_service [Valkyrie::QueryService] (optional) the query service to use
24
+ # @param [Hash] opts the options to send to the query service. Can only be one argument.
25
+ # this argument will be converted to the query in the form of find_by_#{opts.keys.first}
26
+ # @return [Valkyrie::Resource]
27
+ def find_by(query_service: Hyrax.query_service, **opts)
28
+ if opts.key?(:id)
29
+ find(opts[:id], query_service: query_service)
30
+ else
31
+ method_name = "find_by_#{opts.keys.first}"
32
+ value = opts[opts.values.first]
33
+ return query_service.send(method_name, value) if query_service.respond_to?(method_name)
34
+ query_service.custom_query.send(method_name, value)
35
+ end
36
+
37
+ rescue Valkyrie::Persistence::ObjectNotFoundError
38
+ nil
39
+ end
40
+ end
41
+
42
+ ##
43
+ # @param query_service [#find_parents]
44
+ #
45
+ # @return [NilClass] when this object does not have a parent.
46
+ # @return [Valkyrie::Resource] when this object has at least one parent.
47
+ def parent(query_service: Hyrax.query_service)
48
+ query_service.find_parents(resource: self).first
49
+ end
50
+
51
+ ##
52
+ # This will persist the object to the repository. Not a complete transaction set up, but will
53
+ # index and notify listeners of metadata update
54
+ #
55
+ # @param [Hyrax::Persister] Valkyrie persister (optional) will default to Hyrax.persister
56
+ # @param [Hyrax::IndexAdapter] Valkyrie index adapter (optional) will default to Hyrax.index_adapter
57
+ # @param [User] user the user to record the event for. Will not set depositor yet
58
+ # @return [Valkyrie::Resource]
59
+ def save(persister: Hyrax.persister, index_adapter: Hyrax.index_adapter, user: ::User.system_user)
60
+ is_new = new_record
61
+ result = persister.save(resource: self)
62
+ return nil unless result.persisted?
63
+ index_adapter.save(resource: result)
64
+ if result.collection?
65
+ Hyrax.publisher.publish('collection.metadata.updated', collection: result, user: user)
66
+ else
67
+ Hyrax.publisher.publish('object.deposited', object: result, user: user) if is_new
68
+ Hyrax.publisher.publish('object.metadata.updated', object: result, user: user)
69
+ end
70
+ # TODO: do we need to replace the properties here?
71
+ self.new_record = false
72
+ self.id = result.id
73
+
74
+ result
75
+ end
76
+ alias create save
77
+ alias update save
78
+
79
+ def save!(**opts)
80
+ raise Valkyrie::Persistence::ObjectNotFoundError unless save(**opts)
81
+ end
82
+ alias create! save!
83
+ alias update! save!
84
+
85
+ ##
86
+ # This will delete the resource and publish its delete event
87
+ #
88
+ # @param [Hyrax::Persister] Valkyrie persister (optional) will default to Hyrax.persister
89
+ # @param [Hyrax::IndexAdapter] Valkyrie index adapter (optional) will default to Hyrax.index_adapter
90
+ # @param [User] user the user to record the event for. Will not set depositor yet
91
+ # @return [Boolean]
92
+ def destroy(persister: Hyrax.persister, index_adapter: Hyrax.index_adapter, user: ::User.system_user)
93
+ return false unless persisted?
94
+ persister.delete(resource: self)
95
+ index_adapter.delete(resource: self)
96
+ Hyrax.publisher.publish('object.deleted', object: self, user: user)
97
+ true
98
+ end
99
+
100
+ def destroy!(**opts)
101
+ raise Valkyrie::Persistence::ObjectNotFoundError unless destroy(**opts)
102
+ end
103
+ end
104
+ end
@@ -26,7 +26,8 @@ module Hyrax
26
26
  # only includes ids of ordered members.
27
27
  def ordered_member_ids
28
28
  return [] if id.blank?
29
- @ordered_member_ids ||= query_for_ordered_ids
29
+ # Valkyrie members are always ordered
30
+ @ordered_member_ids ||= valkyrie? ? member_ids : query_for_ordered_ids
30
31
  end
31
32
 
32
33
  private
@@ -74,10 +74,17 @@ module Hyrax
74
74
  Hyrax::ModelRegistry.work_classes.include?(hydra_model)
75
75
  end
76
76
 
77
+ ##
78
+ # @return [Boolean]
79
+ def valkyrie?
80
+ self['valkyrie_bsi']
81
+ end
82
+
77
83
  # Method to return the model
78
84
  def hydra_model(classifier: nil)
79
- first('has_model_ssim')&.safe_constantize ||
80
- model_classifier(classifier).classifier(self).best_model
85
+ model = first('has_model_ssim')&.safe_constantize
86
+ model = (first('has_model_ssim')&.+ 'Resource')&.safe_constantize if Hyrax.config.valkyrie_transition?
87
+ model || model_classifier(classifier).classifier(self).best_model
81
88
  end
82
89
 
83
90
  def depositor(default = '')
@@ -135,6 +142,10 @@ module Hyrax
135
142
  self['visibility_ssi'] == indexed_lease_visibility
136
143
  end
137
144
 
145
+ def extensions_and_mime_types
146
+ JSON.parse(self['extensions_and_mime_types_ssm'].first).map(&:with_indifferent_access) if self['extensions_and_mime_types_ssm']
147
+ end
148
+
138
149
  private
139
150
 
140
151
  def model_classifier(classifier)