hyrax 3.2.0 → 3.3.0

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 (167) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +3 -6
  3. data/.dassie/.env +1 -2
  4. data/.dassie/Gemfile +7 -3
  5. data/.dassie/app/models/user.rb +0 -2
  6. data/.dassie/config/analytics.yml +12 -5
  7. data/.dassie/config/environments/development.rb +2 -0
  8. data/.dassie/config/initializers/hyrax.rb +2 -0
  9. data/.dassie/db/migrate/20210921150120_enable_uuid_extension.valkyrie_engine.rb +7 -0
  10. data/.dassie/db/migrate/20210921150121_create_orm_resources.valkyrie_engine.rb +19 -0
  11. data/.dassie/db/migrate/20210921150122_add_model_type_to_orm_resources.valkyrie_engine.rb +7 -0
  12. data/.dassie/db/migrate/20210921150123_change_model_type_to_internal_model.valkyrie_engine.rb +7 -0
  13. data/.dassie/db/migrate/20210921150124_create_path_gin_index.valkyrie_engine.rb +7 -0
  14. data/.dassie/db/migrate/20210921150125_create_internal_resource_index.valkyrie_engine.rb +7 -0
  15. data/.dassie/db/migrate/20210921150126_create_updated_at_index.valkyrie_engine.rb +7 -0
  16. data/.dassie/db/migrate/20210921150127_add_optimistic_locking_to_orm_resources.valkyrie_engine.rb +7 -0
  17. data/.dassie/db/migrate/20211130181150_create_default_administrative_set.rb +8 -0
  18. data/.dassie/db/schema.rb +20 -1
  19. data/.env +7 -4
  20. data/.github/workflows/main.yml +17 -0
  21. data/.github/workflows/release.yml +17 -0
  22. data/.gitignore +1 -0
  23. data/.regen +1 -1
  24. data/CONTAINERS.md +13 -10
  25. data/README.md +37 -0
  26. data/app/assets/javascripts/hyrax/admin/graphs.es6 +34 -37
  27. data/app/assets/javascripts/hyrax/analytics_events.js +69 -0
  28. data/app/assets/javascripts/hyrax/collapse.js +24 -0
  29. data/app/assets/javascripts/hyrax/collections.js +1 -2
  30. data/app/assets/javascripts/hyrax/ga_events.js +2 -8
  31. data/app/assets/javascripts/hyrax/reports-buttons.js +33 -0
  32. data/app/assets/javascripts/hyrax.js +2 -1
  33. data/app/assets/stylesheets/_bootstrap-default-overrides.scss +9 -0
  34. data/app/authorities/qa/authorities/collections.rb +4 -5
  35. data/app/authorities/qa/authorities/find_works.rb +1 -1
  36. data/app/controllers/concerns/hyrax/breadcrumbs_for_collection_analytics.rb +26 -0
  37. data/app/controllers/concerns/hyrax/breadcrumbs_for_works_analytics.rb +26 -0
  38. data/app/controllers/concerns/hyrax/controller.rb +22 -0
  39. data/app/controllers/hyrax/admin/analytics/analytics_controller.rb +40 -0
  40. data/app/controllers/hyrax/admin/analytics/collection_reports_controller.rb +61 -0
  41. data/app/controllers/hyrax/admin/analytics/work_reports_controller.rb +122 -0
  42. data/app/controllers/hyrax/collections_controller.rb +4 -1
  43. data/app/controllers/hyrax/dashboard/collections_controller.rb +15 -6
  44. data/app/controllers/hyrax/dashboard_controller.rb +8 -0
  45. data/app/controllers/hyrax/stats_controller.rb +3 -1
  46. data/app/forms/hyrax/forms/pcdm_collection_form.rb +3 -0
  47. data/app/indexers/hyrax/valkyrie_file_set_indexer.rb +1 -1
  48. data/app/jobs/characterize_job.rb +28 -1
  49. data/app/jobs/valkyrie_ingest_job.rb +56 -0
  50. data/app/models/concerns/hyrax/ability.rb +26 -5
  51. data/app/models/concerns/hyrax/solr_document/metadata.rb +1 -0
  52. data/app/models/file_download_stat.rb +4 -4
  53. data/app/models/hyrax/default_administrative_set.rb +42 -0
  54. data/app/models/hyrax/statistic.rb +31 -4
  55. data/app/presenters/hyrax/admin/dashboard_presenter.rb +8 -6
  56. data/app/presenters/hyrax/admin/repository_growth_presenter.rb +10 -5
  57. data/app/presenters/hyrax/admin/user_activity_presenter.rb +8 -12
  58. data/app/presenters/hyrax/file_set_presenter.rb +2 -0
  59. data/app/presenters/hyrax/menu_presenter.rb +4 -0
  60. data/app/presenters/hyrax/pcdm_member_presenter_factory.rb +1 -1
  61. data/app/presenters/hyrax/work_show_presenter.rb +5 -2
  62. data/app/presenters/hyrax/work_usage.rb +1 -0
  63. data/app/search_builders/hyrax/README.md +1 -1
  64. data/app/search_builders/hyrax/dashboard/collections_search_builder.rb +1 -1
  65. data/app/search_builders/hyrax/my/collections_search_builder.rb +1 -1
  66. data/app/services/hyrax/admin_set_create_service.rb +76 -14
  67. data/app/services/hyrax/analytics/google/events.rb +37 -0
  68. data/app/services/hyrax/analytics/google/events_daily.rb +72 -0
  69. data/app/services/hyrax/analytics/google/visits.rb +44 -0
  70. data/app/services/hyrax/analytics/google/visits_daily.rb +49 -0
  71. data/app/services/hyrax/analytics/google.rb +204 -0
  72. data/app/services/hyrax/analytics/matomo.rb +193 -0
  73. data/app/services/hyrax/analytics/results.rb +79 -0
  74. data/app/services/hyrax/analytics.rb +12 -82
  75. data/app/services/hyrax/characterization/valkyrie_characterization_service.rb +134 -0
  76. data/app/services/hyrax/collections/nested_collection_query_service.rb +8 -3
  77. data/app/services/hyrax/listeners/acl_index_listener.rb +3 -1
  78. data/app/services/hyrax/listeners/active_fedora_acl_index_listener.rb +3 -1
  79. data/app/services/hyrax/listeners/batch_notification_listener.rb +3 -1
  80. data/app/services/hyrax/listeners/file_metadata_listener.rb +19 -0
  81. data/app/services/hyrax/listeners/file_set_lifecycle_listener.rb +6 -2
  82. data/app/services/hyrax/listeners/file_set_lifecycle_notification_listener.rb +6 -2
  83. data/app/services/hyrax/listeners/member_cleanup_listener.rb +3 -0
  84. data/app/services/hyrax/listeners/metadata_index_listener.rb +9 -3
  85. data/app/services/hyrax/listeners/object_lifecycle_listener.rb +9 -3
  86. data/app/services/hyrax/listeners/proxy_deposit_listener.rb +3 -1
  87. data/app/services/hyrax/listeners/trophy_cleanup_listener.rb +3 -0
  88. data/app/services/hyrax/listeners/workflow_listener.rb +3 -1
  89. data/app/services/hyrax/listeners.rb +8 -0
  90. data/app/services/hyrax/restriction_service.rb +4 -0
  91. data/app/services/hyrax/statistics/users/over_time.rb +8 -5
  92. data/app/services/hyrax/statistics/works/over_time.rb +10 -0
  93. data/app/services/hyrax/work_uploads_handler.rb +4 -1
  94. data/app/views/hyrax/admin/analytics/_date_range_form.html.erb +11 -0
  95. data/app/views/hyrax/admin/analytics/collection_reports/_custom_range.html.erb +39 -0
  96. data/app/views/hyrax/admin/analytics/collection_reports/_monthly_summary.html.erb +48 -0
  97. data/app/views/hyrax/admin/analytics/collection_reports/_summary.html.erb +55 -0
  98. data/app/views/hyrax/admin/analytics/collection_reports/_top_collections.html.erb +55 -0
  99. data/app/views/hyrax/admin/analytics/collection_reports/index.html.erb +70 -0
  100. data/app/views/hyrax/admin/analytics/collection_reports/show.html.erb +94 -0
  101. data/app/views/hyrax/admin/analytics/work_reports/_custom_range.html.erb +43 -0
  102. data/app/views/hyrax/admin/analytics/work_reports/_monthly_summary.html.erb +35 -0
  103. data/app/views/hyrax/admin/analytics/work_reports/_summary.html.erb +60 -0
  104. data/app/views/hyrax/admin/analytics/work_reports/_top_file_set_downloads.html.erb +33 -0
  105. data/app/views/hyrax/admin/analytics/work_reports/_top_works.html.erb +40 -0
  106. data/app/views/hyrax/admin/analytics/work_reports/_work_counts.html.erb +18 -0
  107. data/app/views/hyrax/admin/analytics/work_reports/_work_files.html.erb +41 -0
  108. data/app/views/hyrax/admin/analytics/work_reports/index.html.erb +77 -0
  109. data/app/views/hyrax/admin/analytics/work_reports/show.html.erb +90 -0
  110. data/app/views/hyrax/admin/stats/show.html.erb +1 -1
  111. data/app/views/hyrax/base/_relationships_parent_row.html.erb +0 -1
  112. data/app/views/hyrax/base/show.html.erb +6 -0
  113. data/app/views/hyrax/collections/show.html.erb +4 -0
  114. data/app/views/hyrax/dashboard/_repository_growth.html.erb +5 -5
  115. data/app/views/hyrax/dashboard/_resource_type_graph.html.erb +41 -0
  116. data/app/views/hyrax/dashboard/_sidebar.html.erb +4 -1
  117. data/app/views/hyrax/dashboard/_tabs.html.erb +11 -0
  118. data/app/views/hyrax/dashboard/_user_activity.html.erb +17 -23
  119. data/app/views/hyrax/dashboard/_user_activity_graph.html.erb +55 -0
  120. data/app/views/hyrax/dashboard/_visibility_graph.html.erb +31 -0
  121. data/app/views/hyrax/dashboard/_work_type_graph.html.erb +41 -0
  122. data/app/views/hyrax/dashboard/collections/_form.html.erb +2 -1
  123. data/app/views/hyrax/dashboard/show_admin.html.erb +24 -45
  124. data/app/views/hyrax/dashboard/sidebar/_activity.html.erb +22 -0
  125. data/app/views/hyrax/file_sets/_actions.html.erb +4 -3
  126. data/app/views/hyrax/file_sets/show.html.erb +6 -0
  127. data/app/views/hyrax/my/collections/index.html.erb +1 -1
  128. data/app/views/hyrax/stats/_downloads.html.erb +18 -0
  129. data/app/views/hyrax/stats/_pageviews.html.erb +18 -0
  130. data/app/views/hyrax/stats/work.html.erb +17 -9
  131. data/app/views/layouts/_head_tag_content.html.erb +7 -2
  132. data/app/views/{_ga.html.erb → shared/_ga.html.erb} +3 -7
  133. data/app/views/shared/_matomo.html.erb +15 -0
  134. data/chart/hyrax/Chart.yaml +1 -1
  135. data/chart/hyrax/values.yaml +1 -1
  136. data/config/i18n-tasks.yml +2 -2
  137. data/config/initializers/listeners.rb +5 -5
  138. data/config/locales/hyrax.de.yml +194 -0
  139. data/config/locales/hyrax.en.yml +190 -12
  140. data/config/locales/hyrax.es.yml +194 -0
  141. data/config/locales/hyrax.fr.yml +194 -0
  142. data/config/locales/hyrax.it.yml +194 -0
  143. data/config/locales/hyrax.pt-BR.yml +194 -0
  144. data/config/locales/hyrax.zh.yml +194 -0
  145. data/config/routes.rb +4 -0
  146. data/docker-compose.yml +3 -1
  147. data/documentation/developing-your-hyrax-based-app.md +2 -2
  148. data/documentation/legacyREADME.md +1 -1
  149. data/hyrax.gemspec +3 -1
  150. data/lib/generators/hyrax/templates/config/analytics.yml +13 -7
  151. data/lib/generators/hyrax/templates/config/initializers/hyrax.rb +0 -13
  152. data/lib/generators/hyrax/templates/db/migrate/20211130181150_create_default_administrative_set.rb.erb +8 -0
  153. data/lib/generators/hyrax/work/templates/feature_spec.rb.erb +3 -1
  154. data/lib/hyrax/configuration.rb +67 -5
  155. data/lib/hyrax/engine.rb +7 -6
  156. data/lib/hyrax/publisher.rb +4 -0
  157. data/lib/hyrax/transactions/admin_set_create.rb +22 -0
  158. data/lib/hyrax/transactions/container.rb +11 -0
  159. data/lib/hyrax/version.rb +1 -1
  160. data/lib/tasks/regenerate_derivatives.rake +1 -1
  161. data/lib/wings/setup.rb +15 -0
  162. data/lib/wings/valkyrie/persister.rb +16 -0
  163. data/template.rb +1 -1
  164. data/vendor/assets/javascripts/morris/morris.min.js +1 -7
  165. data/vendor/assets/stylesheets/morris.js/0.5.1/morris.css +1 -1
  166. metadata +87 -11
  167. data/app/views/hyrax/dashboard/_repository_objects.html.erb +0 -28
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hyrax::Characterization::ValkyrieCharacterizationService
4
+ ##
5
+ # @api public
6
+ # @param [Hyrax::FileMetadata] metadata which has properties to recieve characterization values
7
+ # @param [Valkyrie::StorageAdapter::StreamFile] source to run characterization against
8
+ # @param [Hash] options the options pass to characterization
9
+ # @option options [Hash{Symbol => Symbol}] parser_mapping
10
+ # @option options [Hydra::Works::Characterization::FitsDocument] parser
11
+ # @option options [Symbol] ch12n_tool
12
+ #
13
+ # @return [void]
14
+ def self.run(metadata:, file:, user: ::User.system_user, **options)
15
+ new(metadata: metadata, file: file, **options).characterize
16
+ saved = Hyrax.persister.save(resource: metadata)
17
+ Hyrax.publisher.publish('object.metadata.updated', object: saved, user: user)
18
+ end
19
+
20
+ ##
21
+ # @!attribute [rw] source
22
+ # @return [Valkyrie::StorageAdapter::StreamFile]
23
+ # @!attribute [rw] metadata
24
+ # @return [Hyrax::FileMetadata]
25
+ # @!attribute [rw] parser
26
+ # @return [Hydra::Works::Characterization::FitsDocument]
27
+ # @!attribute [rw] source
28
+ # @return [Valkyrie::StorageAdapter::StreamFile]
29
+ # @!attribute [rw] tools
30
+ # @todo clarify what this is for. it gets passed to {#characterize}
31
+ # on the characterizer, but it's not clear how to customize
32
+ # effectively.
33
+ # @return [Symbol]
34
+ attr_accessor :mapping, :metadata, :parser, :source, :tools
35
+
36
+ ##
37
+ # @api private
38
+ def initialize(metadata:, # rubocop:disable Metrics/ParameterLists
39
+ file:,
40
+ characterizer: Hydra::FileCharacterization,
41
+ parser_mapping: Hydra::Works::Characterization.mapper,
42
+ parser: Hydra::Works::Characterization::FitsDocument.new)
43
+ @characterizer = characterizer
44
+ @metadata = metadata
45
+ @source = file
46
+ @mapping = parser_mapping
47
+ @parser = parser
48
+ @tools = :fits
49
+ end
50
+
51
+ ##
52
+ # @api private
53
+ #
54
+ # Coerce given source into a type that can be passed to Hydra::FileCharacterization
55
+ # Use Hydra::FileCharacterization to extract metadata (an OM XML document)
56
+ # Get the terms (and their values) from the extracted metadata
57
+ # Assign the values of the terms to the properties of the metadata object
58
+ #
59
+ # @return [void]
60
+ def characterize
61
+ terms = parse_metadata(extract_metadata(content))
62
+ apply_metadata(terms)
63
+ end
64
+
65
+ protected
66
+
67
+ def content
68
+ source.rewind
69
+ source.read
70
+ end
71
+
72
+ def extract_metadata(content)
73
+ @characterizer.characterize(content, file_name, tools) do |cfg|
74
+ cfg[:fits] = Hydra::Derivatives.fits_path
75
+ end
76
+ end
77
+
78
+ def file_name
79
+ metadata.original_filename
80
+ end
81
+
82
+ def parse_metadata(metadata)
83
+ doc = parser
84
+ doc.ng_xml = Nokogiri::XML(metadata) if metadata.present?
85
+ doc.__cleanup__ if doc.respond_to? :__cleanup__
86
+ characterization_terms(doc)
87
+ end
88
+
89
+ # Get proxy terms and values from the parser
90
+ def characterization_terms(doc)
91
+ h = {}
92
+
93
+ doc.class.terminology.terms.each_pair do |key, _target|
94
+ begin
95
+ h[key] = doc.public_send(key)
96
+ rescue NoMethodError
97
+ next
98
+ end
99
+ end
100
+
101
+ h.compact
102
+ end
103
+
104
+ # Assign values of the instance properties from the metadata mapping :prop => val
105
+ # @return [Hash]
106
+ def apply_metadata(terms)
107
+ terms.each_pair do |term, value|
108
+ property = property_for(term)
109
+ next if property.nil?
110
+
111
+ Array(value).each { |v| append_property_value(property, v) }
112
+ end
113
+ end
114
+
115
+ # Check parser_config then self for matching term.
116
+ # Return property symbol or nil
117
+ def property_for(term)
118
+ if mapping.key?(term) && metadata.respond_to?(mapping[term])
119
+ mapping[term]
120
+ elsif metadata.respond_to?(term)
121
+ term
122
+ end
123
+ end
124
+
125
+ ##
126
+ # @todo push exceptional per-property behavior into the mapping somehow?
127
+ def append_property_value(property, value)
128
+ # We don't want multiple mime_types; this overwrites each time to accept last value
129
+ value = Array(metadata.public_send(property)) + [value] unless property == :mime_type
130
+ # We don't want multiple heights / widths, pick the max
131
+ value = value.map(&:to_i).max.to_s if property == :height || property == :width
132
+ metadata.public_send("#{property}=", value)
133
+ end
134
+ end
@@ -111,6 +111,9 @@ module Hyrax
111
111
  def self.clean_lucene_error(builder:)
112
112
  # TODO: Need to investigate further to understand why these particular queries
113
113
  # using the where cause fail when others in the app apparently work
114
+ #
115
+ # Perhaps see <https://github.com/projectblacklight/blacklight/blob/064302f73eee4baae4d2abf863c68317d3efb5b7/lib/blacklight/solr/search_builder_behavior.rb#L84-L102>.
116
+ # This can be averted by using #with in at least some cases?
114
117
  query = builder.query.to_hash
115
118
  query['q'] = query['q'].gsub('{!lucene}', '') if query.key?('q')
116
119
  query
@@ -175,9 +178,11 @@ module Hyrax
175
178
  # => 1) First we find all the collections with this child in the path, sort the results in descending order, and take the first result.
176
179
  # note: We need to include works in this search. They are included in the depth validations in
177
180
  # the indexer, so we do NOT use collection search builder here.
178
- builder = Hyrax::SearchBuilder.new(scope).where("#{Samvera::NestingIndexer.configuration.solr_field_name_for_storing_pathnames}:/.*#{child.id}.*/")
179
- builder.query[:sort] = "#{Samvera::NestingIndexer.configuration.solr_field_name_for_deepest_nested_depth} desc"
180
- builder.query[:rows] = 1
181
+ builder = Hyrax::SearchBuilder.new(scope).with({
182
+ q: "#{Samvera::NestingIndexer.configuration.solr_field_name_for_storing_pathnames}:/.*#{child.id}.*/",
183
+ sort: "#{Samvera::NestingIndexer.configuration.solr_field_name_for_deepest_nested_depth} desc"
184
+ })
185
+ builder.rows = 1
181
186
  query = clean_lucene_error(builder: builder)
182
187
  response = scope.repository.search(query).documents.first
183
188
 
@@ -11,7 +11,9 @@ module Hyrax
11
11
  ##
12
12
  # Re-index the resource for the updated ACL.
13
13
  #
14
- # @param event [Dry::Event]
14
+ # Called when 'object.acl.updated' event is published
15
+ # @param [Dry::Events::Event] event
16
+ # @return [void]
15
17
  def on_object_acl_updated(event)
16
18
  return unless event[:result] == :success # do nothing on failure
17
19
  Hyrax.index_adapter.save(resource: event[:acl].resource)
@@ -11,7 +11,9 @@ module Hyrax
11
11
  ##
12
12
  # Re-index the resource for the updated ACL.
13
13
  #
14
- # @param event [Dry::Event]
14
+ # Called when 'object.acl.updated' event is published
15
+ # @param [Dry::Events::Event] event
16
+ # @return [void]
15
17
  def on_object_acl_updated(event)
16
18
  return if Hyrax.config.disable_wings
17
19
  return unless event[:result] == :success # do nothing on failure
@@ -8,7 +8,9 @@ module Hyrax
8
8
  ##
9
9
  # Notify requesting users of batch success/failure
10
10
  #
11
- # @param event [Dry::Event]
11
+ # Called when 'batch.created' event is published
12
+ # @param [Dry::Events::Event] event
13
+ # @return [void]
12
14
  def on_batch_created(event)
13
15
  case event[:result]
14
16
  when :success
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrax
4
+ module Listeners
5
+ ##
6
+ # Listens for events related to Hyrax::FileMetadata
7
+ class FileMetadataListener
8
+ ##
9
+ # Called when 'object.file.uploaded' event is published
10
+ # @param [Dry::Events::Event] event
11
+ # @return [void]
12
+ def on_object_file_uploaded(event)
13
+ Hyrax.config
14
+ .characterization_service
15
+ .run(metadata: event[:metadata], file: event[:metadata].file)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -6,13 +6,17 @@ module Hyrax
6
6
  # Listens for events related to Hydra Works FileSets
7
7
  class FileSetLifecycleListener
8
8
  ##
9
- # @param event [Dry::Event]
9
+ # Called when 'file.set.attached' event is published
10
+ # @param [Dry::Events::Event] event
11
+ # @return [void]
10
12
  def on_file_set_attached(event)
11
13
  FileSetAttachedEventJob.perform_later(event[:file_set], event[:user])
12
14
  end
13
15
 
14
16
  ##
15
- # @param event [Dry::Event]
17
+ # Called when 'file.set.restored' event is published
18
+ # @param [Dry::Events::Event] event
19
+ # @return [void]
16
20
  def on_file_set_restored(event)
17
21
  ContentRestoredVersionEventJob
18
22
  .perform_later(event[:file_set], event[:user], event[:revision])
@@ -9,7 +9,9 @@ module Hyrax
9
9
  ##
10
10
  # Send a notification to the depositor for failed checksum audits.
11
11
  #
12
- # @param event [Dry::Event]
12
+ # Called when 'file.set.audited' event is published
13
+ # @param [Dry::Events::Event] event
14
+ # @return [void]
13
15
  def on_file_set_audited(event)
14
16
  return unless event[:result] == :failure # do nothing on success
15
17
 
@@ -24,7 +26,9 @@ module Hyrax
24
26
  # Send a notification to the depositing user for FileSet url import
25
27
  # failures.
26
28
  #
27
- # @param event [Dry::Event]
29
+ # Called when 'file.set.url.imported' event is published
30
+ # @param [Dry::Events::Event] event
31
+ # @return [void]
28
32
  def on_file_set_url_imported(event)
29
33
  Hyrax::ImportUrlFailureService.new(event[:file_set], event[:user]).call if
30
34
  event[:result] == :failure
@@ -5,6 +5,9 @@ module Hyrax
5
5
  ##
6
6
  # Listens for object deleted events and cleans up associated members
7
7
  class MemberCleanupListener
8
+ # Called when 'object.deleted' event is published
9
+ # @param [Dry::Events::Event] event
10
+ # @return [void]
8
11
  def on_object_deleted(event)
9
12
  return unless event.payload.key?(:object) # legacy callback
10
13
  return if event[:object].is_a?(ActiveFedora::Base) # handled by legacy code
@@ -14,7 +14,9 @@ module Hyrax
14
14
  ##
15
15
  # Re-index the resource.
16
16
  #
17
- # @param event [Dry::Event]
17
+ # Called when 'collection.metadata.updated' event is published
18
+ # @param [Dry::Events::Event] event
19
+ # @return [void]
18
20
  def on_collection_metadata_updated(event)
19
21
  return unless resource? event[:collection]
20
22
  Hyrax.index_adapter.save(resource: event[:collection])
@@ -23,7 +25,9 @@ module Hyrax
23
25
  ##
24
26
  # Re-index the resource.
25
27
  #
26
- # @param event [Dry::Event]
28
+ # Called when 'object.metadata.updated' event is published
29
+ # @param [Dry::Events::Event] event
30
+ # @return [void]
27
31
  def on_object_metadata_updated(event)
28
32
  return unless resource? event[:object]
29
33
  Hyrax.index_adapter.save(resource: event[:object])
@@ -32,7 +36,9 @@ module Hyrax
32
36
  ##
33
37
  # Remove the resource from the index.
34
38
  #
35
- # @param event [Dry::Event]
39
+ # Called when 'object.deleted' event is published
40
+ # @param [Dry::Events::Event] event
41
+ # @return [void]
36
42
  def on_object_deleted(event)
37
43
  return unless resource?(event.payload[:object])
38
44
  Hyrax.index_adapter.delete(resource: event[:object])
@@ -6,19 +6,25 @@ module Hyrax
6
6
  # Listens for events related to the PCDM Object lifecycles.
7
7
  class ObjectLifecycleListener
8
8
  ##
9
- # @param event [Dry::Event]
9
+ # Called when 'object.deleted' event is published
10
+ # @param [Dry::Events::Event] event
11
+ # @return [void]
10
12
  def on_object_deleted(event)
11
13
  ContentDeleteEventJob.perform_later(event[:id].to_s, event[:user])
12
14
  end
13
15
 
14
16
  ##
15
- # @param event [Dry::Event]
17
+ # Called when 'object.deposited' event is published
18
+ # @param [Dry::Events::Event] event
19
+ # @return [void]
16
20
  def on_object_deposited(event)
17
21
  ContentDepositEventJob.perform_later(event[:object], event[:user])
18
22
  end
19
23
 
20
24
  ##
21
- # @param event [Dry::Event]
25
+ # Called when 'object.metadata.updated' event is published
26
+ # @param [Dry::Events::Event] event
27
+ # @return [void]
22
28
  def on_object_metadata_updated(event)
23
29
  ContentUpdateEventJob.perform_later(event[:object], event[:user])
24
30
  end
@@ -7,7 +7,9 @@ module Hyrax
7
7
  # deposits an item `on_behalf_of` another, ensures transfer is handled.
8
8
  class ProxyDepositListener
9
9
  ##
10
- # @param event [Dry::Event]
10
+ # Called when 'object.deposited' event is published
11
+ # @param [Dry::Events::Event] event
12
+ # @return [void]
11
13
  def on_object_deposited(event)
12
14
  return if event[:object].try(:on_behalf_of).blank? ||
13
15
  (event[:object].on_behalf_of == event[:object].depositor)
@@ -5,6 +5,9 @@ module Hyrax
5
5
  ##
6
6
  # Listens for object deleted events and cleans up associated members
7
7
  class TrophyCleanupListener
8
+ # Called when 'object.deleted' event is published
9
+ # @param [Dry::Events::Event] event
10
+ # @return [void]
8
11
  def on_object_deleted(event)
9
12
  Trophy.where(work_id: event[:id]).destroy_all
10
13
  rescue StandardError => err
@@ -21,7 +21,9 @@ module Hyrax
21
21
  end
22
22
 
23
23
  ##
24
- # @param event [Dry::Event]
24
+ # Called when 'object.deposited' event is published
25
+ # @param [Dry::Events::Event] event
26
+ # @return [void]
25
27
  def on_object_deposited(event)
26
28
  return Rails.logger.warn("Skipping workflow initialization for #{event[:object]}; no user is given\n\t#{event}") if
27
29
  event[:user].blank?
@@ -7,11 +7,19 @@ module Hyrax
7
7
  #
8
8
  # You may need to register a listener as autoload. See
9
9
  # ./app/services/hyrax/listeners.rb
10
+ #
11
+ # When an instance of a listener class is registered with
12
+ # Dry::Events::Publisher#subscribe, its method(s) will be called when a event
13
+ # is published that maps to the method name using the pattern:
14
+ # on_event_fired => 'event.fired'
15
+ #
16
+ # @see https://dry-rb.org/gems/dry-events/0.2/#event-listeners
10
17
  module Listeners
11
18
  extend ActiveSupport::Autoload
12
19
 
13
20
  autoload :AclIndexListener
14
21
  autoload :BatchNotificationListener
22
+ autoload :FileMetadataListener
15
23
  autoload :FileSetLifecycleListener
16
24
  autoload :FileSetLifecycleNotificationListener
17
25
  autoload :MemberCleanupListener
@@ -2,6 +2,10 @@
2
2
  module Hyrax
3
3
  class RestrictionService
4
4
  class << self
5
+ ##
6
+ # @note needed to construct SearchBuilders using self in Blacklight 7+
7
+ delegate :blacklight_config, to: :config
8
+
5
9
  private
6
10
 
7
11
  def presenter_class
@@ -8,9 +8,8 @@ module Hyrax
8
8
  Enumerator.new(size) do |y|
9
9
  x = @x_min
10
10
  while x <= @x_max
11
- bottom = x
11
+ y.yield [@x_output.call(x), point(x)]
12
12
  x += @delta_x.days
13
- y.yield [@x_output.call(x), point(bottom, x)]
14
13
  end
15
14
  end
16
15
  end
@@ -21,9 +20,13 @@ module Hyrax
21
20
  ::User.registered
22
21
  end
23
22
 
24
- # Override to make an activerecord date range query
25
- def query(min, max)
26
- { created_at: min..max }
23
+ # Overridden to search one day at a time
24
+ def query(date_string)
25
+ { created_at: date_string.to_date.beginning_of_day..date_string.to_date.end_of_day }
26
+ end
27
+
28
+ def point(date_string)
29
+ relation.where(query(date_string)).count
27
30
  end
28
31
  end
29
32
  end
@@ -3,6 +3,16 @@ module Hyrax
3
3
  module Statistics
4
4
  module Works
5
5
  class OverTime < Statistics::OverTime
6
+ def points
7
+ Enumerator.new(size) do |y|
8
+ x = @x_min
9
+ while x <= @x_max
10
+ y.yield [@x_output.call(x), point(@x_min, x)]
11
+ x += @delta_x.days
12
+ end
13
+ end
14
+ end
15
+
6
16
  private
7
17
 
8
18
  def relation
@@ -114,8 +114,11 @@ module Hyrax
114
114
  file_set.permission_manager.acl.save if file_set.permission_manager.acl.pending_changes?
115
115
  append_to_work(file_set)
116
116
 
117
- IngestJob.perform_later(wrap_file(file, file_set))
117
+ ValkyrieIngestJob.perform_later(file)
118
+
119
+ # this triggers the re-index
118
120
  Hyrax.publisher.publish('object.metadata.updated', object: file_set, user: file.user)
121
+
119
122
  { file_set: file_set, user: file.user }
120
123
  end
121
124
 
@@ -0,0 +1,11 @@
1
+ <div class="panel panel-default">
2
+ <div class="panel-heading"><h4><%= t('.date_range_heading') %></h4></div>
3
+ <div class="panel-body">
4
+ <%= form_tag(redirect_path, method: :get, class: "form-inline") do %>
5
+ <%= t('.start_date') %>: <%= date_field_tag :start_date, "", class: 'datepicker form-control', placeholder: 'mm/dd/yyyy', required: true %>
6
+ <%= t('.end_date') %>: <%= date_field_tag :end_date, "", class: 'datepicker form-control', placeholder: 'mm/dd/yyyy', required: true %>
7
+ <%= submit_tag "#{t('.set_date_range')}", class: 'btn btn-primary' %>
8
+ <%= link_to "#{t('.reset_date_range')}", redirect_path if params[:start_date] %>
9
+ <% end %>
10
+ </div>
11
+ </div>
@@ -0,0 +1,39 @@
1
+ <div class="panel panel-default">
2
+ <div class="panel-heading"><h4><%= t('.summary_heading') %></h4></div>
3
+ <div class="panel-body">
4
+ <table class="table table-striped">
5
+ <thead>
6
+ <tr>
7
+ <th>&nbsp;</th>
8
+ <th><%= @start_date.to_date.strftime("%B %d, %Y") %> through <%= @end_date.to_date.strftime("%B %d, %Y") %></th>
9
+ </tr>
10
+ </thead>
11
+ <tbody>
12
+ <% if @pageviews %>
13
+ <tr>
14
+ <td><b><%= t('.collection_home_page_views') %></b></td>
15
+ <td><%= @pageviews.range(@start_date.to_date, @end_date.to_date) %></td>
16
+ </tr>
17
+ <% end %>
18
+ <% if @work_page_views %>
19
+ <tr>
20
+ <td><b><%= t('.work_views') %></b></td>
21
+ <td><%= @work_page_views.range(@start_date.to_date, @end_date.to_date) %></td>
22
+ </tr>
23
+ <% end %>
24
+ <% if @downloads %>
25
+ <tr>
26
+ <td><b><%= t('.work_downloads') %></b></td>
27
+ <td><%= @downloads.range(@start_date.to_date, @end_date.to_date) %></td>
28
+ </tr>
29
+ <% end %>
30
+ </tbody>
31
+ </table>
32
+ </div>
33
+ </div>
34
+
35
+ <% if params[:start_date] %>
36
+ <% if @top_collections %>
37
+ <%= render 'top_collections' %>
38
+ <% end %>
39
+ <% end %>
@@ -0,0 +1,48 @@
1
+ <div class="panel panel-default">
2
+ <div class="panel-heading">
3
+ <h4><%= t('.monthly_subtitle') %> <%= Time.zone.today.strftime("%B %Y") %></h4>
4
+ </div>
5
+ <div class="panel-body">
6
+ <table class="table table-striped">
7
+ <thead>
8
+ <tr>
9
+ <th>&nbsp;</th>
10
+ <% @month_names.each do |name| %>
11
+ <th><%= name %></th>
12
+ <% end %>
13
+ </tr>
14
+ </thead>
15
+ <tbody>
16
+ <% if @pageviews %>
17
+ <tr>
18
+ <td><b><%= t('.collection_views') %></b></td>
19
+ <% @month_names.each do |name| %>
20
+ <td><%= @pageviews.month(name.to_date) %></td>
21
+ <% end %>
22
+ </tr>
23
+ <% end %>
24
+ <% if @work_page_views %>
25
+ <tr>
26
+ <td><b><%= t('.work_views') %></b></td>
27
+ <% @month_names.each do |name| %>
28
+ <td><%= @work_page_views.month(name.to_date) %></td>
29
+ <% end %>
30
+ </tr>
31
+ <% end %>
32
+ <% if @downloads %>
33
+ <tr>
34
+ <td><b><%= t('.work_downloads') %></b></td>
35
+ <% @month_names.each do |name| %>
36
+ <td><%= @downloads.month(name.to_date) %></td>
37
+ <% end %>
38
+ </tr>
39
+ <% end %>
40
+
41
+ </tbody>
42
+ </table>
43
+ </div>
44
+ </div>
45
+
46
+
47
+
48
+
@@ -0,0 +1,55 @@
1
+ <div class="panel panel-default">
2
+ <div class="panel-heading">
3
+ <h4><%= t('.subtitle')%></h4>
4
+ </div>
5
+ <div class="panel-body">
6
+ <table class="table table-striped">
7
+ <thead>
8
+ <tr>
9
+ <th>&nbsp;</th>
10
+ <th><%= t('.today') %></th>
11
+ <th><%= t('.this_week') %></th>
12
+ <th><%= t('.this_month') %></th>
13
+ <th><%= t('.this_year') %></th>
14
+ <th><%= t('.all_time') %></th>
15
+ </tr>
16
+ </thead>
17
+ <tbody>
18
+ <% if @pageviews %>
19
+ <tr>
20
+ <td><b><%= t('.collection_home_page_views') %></b></td>
21
+ <td><%= @pageviews.day %></td>
22
+ <td><%= @pageviews.week %></td>
23
+ <td><%= @pageviews.month %></td>
24
+ <td><%= @pageviews.year %></td>
25
+ <td><%= @pageviews.all %></td>
26
+ </tr>
27
+ <% end %>
28
+ <% if @work_page_views %>
29
+ <tr>
30
+ <td><b><%= t('.work_views') %></b></td>
31
+ <td><%= @work_page_views.day %></td>
32
+ <td><%= @work_page_views.week %></td>
33
+ <td><%= @work_page_views.month %></td>
34
+ <td><%= @work_page_views.year %></td>
35
+ <td><%= @work_page_views.all %></td>
36
+ </tr>
37
+ <% end %>
38
+ <% if @downloads %>
39
+ <tr>
40
+ <td><b><%= t('.work_downloads') %></b></td>
41
+ <td><%= @downloads.day %></td>
42
+ <td><%= @downloads.week %></td>
43
+ <td><%= @downloads.month %></td>
44
+ <td><%= @downloads.year %></td>
45
+ <td><%= @downloads.all %></td>
46
+ </tr>
47
+ <% end %>
48
+ </tbody>
49
+ </table>
50
+ </div>
51
+ </div>
52
+
53
+ <% if @top_collections %>
54
+ <%= render 'top_collections' %>
55
+ <% end %>