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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +3 -6
- data/.dassie/.env +1 -2
- data/.dassie/Gemfile +7 -3
- data/.dassie/app/models/user.rb +0 -2
- data/.dassie/config/analytics.yml +12 -5
- data/.dassie/config/environments/development.rb +2 -0
- data/.dassie/config/initializers/hyrax.rb +2 -0
- data/.dassie/db/migrate/20210921150120_enable_uuid_extension.valkyrie_engine.rb +7 -0
- data/.dassie/db/migrate/20210921150121_create_orm_resources.valkyrie_engine.rb +19 -0
- data/.dassie/db/migrate/20210921150122_add_model_type_to_orm_resources.valkyrie_engine.rb +7 -0
- data/.dassie/db/migrate/20210921150123_change_model_type_to_internal_model.valkyrie_engine.rb +7 -0
- data/.dassie/db/migrate/20210921150124_create_path_gin_index.valkyrie_engine.rb +7 -0
- data/.dassie/db/migrate/20210921150125_create_internal_resource_index.valkyrie_engine.rb +7 -0
- data/.dassie/db/migrate/20210921150126_create_updated_at_index.valkyrie_engine.rb +7 -0
- data/.dassie/db/migrate/20210921150127_add_optimistic_locking_to_orm_resources.valkyrie_engine.rb +7 -0
- data/.dassie/db/migrate/20211130181150_create_default_administrative_set.rb +8 -0
- data/.dassie/db/schema.rb +20 -1
- data/.env +7 -4
- data/.github/workflows/main.yml +17 -0
- data/.github/workflows/release.yml +17 -0
- data/.gitignore +1 -0
- data/.regen +1 -1
- data/CONTAINERS.md +13 -10
- data/README.md +37 -0
- data/app/assets/javascripts/hyrax/admin/graphs.es6 +34 -37
- data/app/assets/javascripts/hyrax/analytics_events.js +69 -0
- data/app/assets/javascripts/hyrax/collapse.js +24 -0
- data/app/assets/javascripts/hyrax/collections.js +1 -2
- data/app/assets/javascripts/hyrax/ga_events.js +2 -8
- data/app/assets/javascripts/hyrax/reports-buttons.js +33 -0
- data/app/assets/javascripts/hyrax.js +2 -1
- data/app/assets/stylesheets/_bootstrap-default-overrides.scss +9 -0
- data/app/authorities/qa/authorities/collections.rb +4 -5
- data/app/authorities/qa/authorities/find_works.rb +1 -1
- data/app/controllers/concerns/hyrax/breadcrumbs_for_collection_analytics.rb +26 -0
- data/app/controllers/concerns/hyrax/breadcrumbs_for_works_analytics.rb +26 -0
- data/app/controllers/concerns/hyrax/controller.rb +22 -0
- data/app/controllers/hyrax/admin/analytics/analytics_controller.rb +40 -0
- data/app/controllers/hyrax/admin/analytics/collection_reports_controller.rb +61 -0
- data/app/controllers/hyrax/admin/analytics/work_reports_controller.rb +122 -0
- data/app/controllers/hyrax/collections_controller.rb +4 -1
- data/app/controllers/hyrax/dashboard/collections_controller.rb +15 -6
- data/app/controllers/hyrax/dashboard_controller.rb +8 -0
- data/app/controllers/hyrax/stats_controller.rb +3 -1
- data/app/forms/hyrax/forms/pcdm_collection_form.rb +3 -0
- data/app/indexers/hyrax/valkyrie_file_set_indexer.rb +1 -1
- data/app/jobs/characterize_job.rb +28 -1
- data/app/jobs/valkyrie_ingest_job.rb +56 -0
- data/app/models/concerns/hyrax/ability.rb +26 -5
- data/app/models/concerns/hyrax/solr_document/metadata.rb +1 -0
- data/app/models/file_download_stat.rb +4 -4
- data/app/models/hyrax/default_administrative_set.rb +42 -0
- data/app/models/hyrax/statistic.rb +31 -4
- data/app/presenters/hyrax/admin/dashboard_presenter.rb +8 -6
- data/app/presenters/hyrax/admin/repository_growth_presenter.rb +10 -5
- data/app/presenters/hyrax/admin/user_activity_presenter.rb +8 -12
- data/app/presenters/hyrax/file_set_presenter.rb +2 -0
- data/app/presenters/hyrax/menu_presenter.rb +4 -0
- data/app/presenters/hyrax/pcdm_member_presenter_factory.rb +1 -1
- data/app/presenters/hyrax/work_show_presenter.rb +5 -2
- data/app/presenters/hyrax/work_usage.rb +1 -0
- data/app/search_builders/hyrax/README.md +1 -1
- data/app/search_builders/hyrax/dashboard/collections_search_builder.rb +1 -1
- data/app/search_builders/hyrax/my/collections_search_builder.rb +1 -1
- data/app/services/hyrax/admin_set_create_service.rb +76 -14
- data/app/services/hyrax/analytics/google/events.rb +37 -0
- data/app/services/hyrax/analytics/google/events_daily.rb +72 -0
- data/app/services/hyrax/analytics/google/visits.rb +44 -0
- data/app/services/hyrax/analytics/google/visits_daily.rb +49 -0
- data/app/services/hyrax/analytics/google.rb +204 -0
- data/app/services/hyrax/analytics/matomo.rb +193 -0
- data/app/services/hyrax/analytics/results.rb +79 -0
- data/app/services/hyrax/analytics.rb +12 -82
- data/app/services/hyrax/characterization/valkyrie_characterization_service.rb +134 -0
- data/app/services/hyrax/collections/nested_collection_query_service.rb +8 -3
- data/app/services/hyrax/listeners/acl_index_listener.rb +3 -1
- data/app/services/hyrax/listeners/active_fedora_acl_index_listener.rb +3 -1
- data/app/services/hyrax/listeners/batch_notification_listener.rb +3 -1
- data/app/services/hyrax/listeners/file_metadata_listener.rb +19 -0
- data/app/services/hyrax/listeners/file_set_lifecycle_listener.rb +6 -2
- data/app/services/hyrax/listeners/file_set_lifecycle_notification_listener.rb +6 -2
- data/app/services/hyrax/listeners/member_cleanup_listener.rb +3 -0
- data/app/services/hyrax/listeners/metadata_index_listener.rb +9 -3
- data/app/services/hyrax/listeners/object_lifecycle_listener.rb +9 -3
- data/app/services/hyrax/listeners/proxy_deposit_listener.rb +3 -1
- data/app/services/hyrax/listeners/trophy_cleanup_listener.rb +3 -0
- data/app/services/hyrax/listeners/workflow_listener.rb +3 -1
- data/app/services/hyrax/listeners.rb +8 -0
- data/app/services/hyrax/restriction_service.rb +4 -0
- data/app/services/hyrax/statistics/users/over_time.rb +8 -5
- data/app/services/hyrax/statistics/works/over_time.rb +10 -0
- data/app/services/hyrax/work_uploads_handler.rb +4 -1
- data/app/views/hyrax/admin/analytics/_date_range_form.html.erb +11 -0
- data/app/views/hyrax/admin/analytics/collection_reports/_custom_range.html.erb +39 -0
- data/app/views/hyrax/admin/analytics/collection_reports/_monthly_summary.html.erb +48 -0
- data/app/views/hyrax/admin/analytics/collection_reports/_summary.html.erb +55 -0
- data/app/views/hyrax/admin/analytics/collection_reports/_top_collections.html.erb +55 -0
- data/app/views/hyrax/admin/analytics/collection_reports/index.html.erb +70 -0
- data/app/views/hyrax/admin/analytics/collection_reports/show.html.erb +94 -0
- data/app/views/hyrax/admin/analytics/work_reports/_custom_range.html.erb +43 -0
- data/app/views/hyrax/admin/analytics/work_reports/_monthly_summary.html.erb +35 -0
- data/app/views/hyrax/admin/analytics/work_reports/_summary.html.erb +60 -0
- data/app/views/hyrax/admin/analytics/work_reports/_top_file_set_downloads.html.erb +33 -0
- data/app/views/hyrax/admin/analytics/work_reports/_top_works.html.erb +40 -0
- data/app/views/hyrax/admin/analytics/work_reports/_work_counts.html.erb +18 -0
- data/app/views/hyrax/admin/analytics/work_reports/_work_files.html.erb +41 -0
- data/app/views/hyrax/admin/analytics/work_reports/index.html.erb +77 -0
- data/app/views/hyrax/admin/analytics/work_reports/show.html.erb +90 -0
- data/app/views/hyrax/admin/stats/show.html.erb +1 -1
- data/app/views/hyrax/base/_relationships_parent_row.html.erb +0 -1
- data/app/views/hyrax/base/show.html.erb +6 -0
- data/app/views/hyrax/collections/show.html.erb +4 -0
- data/app/views/hyrax/dashboard/_repository_growth.html.erb +5 -5
- data/app/views/hyrax/dashboard/_resource_type_graph.html.erb +41 -0
- data/app/views/hyrax/dashboard/_sidebar.html.erb +4 -1
- data/app/views/hyrax/dashboard/_tabs.html.erb +11 -0
- data/app/views/hyrax/dashboard/_user_activity.html.erb +17 -23
- data/app/views/hyrax/dashboard/_user_activity_graph.html.erb +55 -0
- data/app/views/hyrax/dashboard/_visibility_graph.html.erb +31 -0
- data/app/views/hyrax/dashboard/_work_type_graph.html.erb +41 -0
- data/app/views/hyrax/dashboard/collections/_form.html.erb +2 -1
- data/app/views/hyrax/dashboard/show_admin.html.erb +24 -45
- data/app/views/hyrax/dashboard/sidebar/_activity.html.erb +22 -0
- data/app/views/hyrax/file_sets/_actions.html.erb +4 -3
- data/app/views/hyrax/file_sets/show.html.erb +6 -0
- data/app/views/hyrax/my/collections/index.html.erb +1 -1
- data/app/views/hyrax/stats/_downloads.html.erb +18 -0
- data/app/views/hyrax/stats/_pageviews.html.erb +18 -0
- data/app/views/hyrax/stats/work.html.erb +17 -9
- data/app/views/layouts/_head_tag_content.html.erb +7 -2
- data/app/views/{_ga.html.erb → shared/_ga.html.erb} +3 -7
- data/app/views/shared/_matomo.html.erb +15 -0
- data/chart/hyrax/Chart.yaml +1 -1
- data/chart/hyrax/values.yaml +1 -1
- data/config/i18n-tasks.yml +2 -2
- data/config/initializers/listeners.rb +5 -5
- data/config/locales/hyrax.de.yml +194 -0
- data/config/locales/hyrax.en.yml +190 -12
- data/config/locales/hyrax.es.yml +194 -0
- data/config/locales/hyrax.fr.yml +194 -0
- data/config/locales/hyrax.it.yml +194 -0
- data/config/locales/hyrax.pt-BR.yml +194 -0
- data/config/locales/hyrax.zh.yml +194 -0
- data/config/routes.rb +4 -0
- data/docker-compose.yml +3 -1
- data/documentation/developing-your-hyrax-based-app.md +2 -2
- data/documentation/legacyREADME.md +1 -1
- data/hyrax.gemspec +3 -1
- data/lib/generators/hyrax/templates/config/analytics.yml +13 -7
- data/lib/generators/hyrax/templates/config/initializers/hyrax.rb +0 -13
- data/lib/generators/hyrax/templates/db/migrate/20211130181150_create_default_administrative_set.rb.erb +8 -0
- data/lib/generators/hyrax/work/templates/feature_spec.rb.erb +3 -1
- data/lib/hyrax/configuration.rb +67 -5
- data/lib/hyrax/engine.rb +7 -6
- data/lib/hyrax/publisher.rb +4 -0
- data/lib/hyrax/transactions/admin_set_create.rb +22 -0
- data/lib/hyrax/transactions/container.rb +11 -0
- data/lib/hyrax/version.rb +1 -1
- data/lib/tasks/regenerate_derivatives.rake +1 -1
- data/lib/wings/setup.rb +15 -0
- data/lib/wings/valkyrie/persister.rb +16 -0
- data/template.rb +1 -1
- data/vendor/assets/javascripts/morris/morris.min.js +1 -7
- data/vendor/assets/stylesheets/morris.js/0.5.1/morris.css +1 -1
- metadata +87 -11
- 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).
|
|
179
|
-
|
|
180
|
-
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
|
@@ -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
|
-
|
|
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
|
-
#
|
|
25
|
-
def query(
|
|
26
|
-
{ created_at:
|
|
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
|
-
|
|
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> </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> </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> </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 %>
|