hyrax 3.2.0 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class ValkyrieIngestJob < Hyrax::ApplicationJob
|
3
|
+
queue_as Hyrax.config.ingest_queue_name
|
4
|
+
|
5
|
+
##
|
6
|
+
# @param [Valkyrie::StorageAdapter::StreamFile] file
|
7
|
+
def perform(file)
|
8
|
+
ingest(file: file)
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
# @param [Valkyrie::StorageAdapter::StreamFile] file
|
13
|
+
#
|
14
|
+
# @return [void]
|
15
|
+
def ingest(file:)
|
16
|
+
file_set = Hyrax.query_service.find_by(id: file.file_set_uri)
|
17
|
+
updated_metadata = upload_file(file: file, file_set: file_set)
|
18
|
+
|
19
|
+
add_file_to_file_set(file_set: file_set, file_metadata: updated_metadata)
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# @todo this should publish something to allow the fileset
|
24
|
+
# to reindex its membership
|
25
|
+
# @param [Hyrax::FileSet] file_set the file set to add to
|
26
|
+
# @param [Hyrax::FileMetadata] file_metadata the metadata object representing
|
27
|
+
# the file to add
|
28
|
+
#
|
29
|
+
# @return [Hyrax::FileSet] updated file set
|
30
|
+
def add_file_to_file_set(file_set:, file_metadata:)
|
31
|
+
file_set.file_ids << file_metadata.id
|
32
|
+
Hyrax.persister.save(resource: file_set)
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# @param [Hyrax::UploadedFile] file
|
37
|
+
# @param [Hyrax::FileSet] file_set
|
38
|
+
#
|
39
|
+
# @return [Hyrax::FileMetadata] the metadata representing the uploaded file
|
40
|
+
def upload_file(file:, file_set:)
|
41
|
+
carrier_wave_sanitized_file = file.uploader.file
|
42
|
+
uploaded = Hyrax.storage_adapter
|
43
|
+
.upload(resource: file_set,
|
44
|
+
file: carrier_wave_sanitized_file,
|
45
|
+
original_filename: carrier_wave_sanitized_file.original_filename)
|
46
|
+
|
47
|
+
file_metadata = Hyrax.custom_queries.find_file_metadata_by(id: uploaded.id)
|
48
|
+
file_metadata.file_set_id = file.file_set_uri
|
49
|
+
file_metadata.file_identifier = uploaded.id
|
50
|
+
file_metadata.size = uploaded.size
|
51
|
+
|
52
|
+
Hyrax.publisher.publish("object.file.uploaded", metadata: file_metadata)
|
53
|
+
|
54
|
+
file_metadata
|
55
|
+
end
|
56
|
+
end
|
@@ -1,7 +1,30 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module Hyrax
|
3
3
|
##
|
4
|
-
# Provides Hyrax's engine level user/group
|
4
|
+
# Provides Hyrax's engine level user/group authorizations.
|
5
|
+
#
|
6
|
+
# Authorization (allow or deny) of the following actions is managed by the
|
7
|
+
# rules defined here:
|
8
|
+
#
|
9
|
+
# - read:
|
10
|
+
# - show:
|
11
|
+
# - edit:
|
12
|
+
# - update:
|
13
|
+
# - create:
|
14
|
+
# - discover:
|
15
|
+
# - manage:
|
16
|
+
# - download:
|
17
|
+
# - destroy:
|
18
|
+
# - collect:
|
19
|
+
# - toggle_trophy:
|
20
|
+
# - transfer:
|
21
|
+
# - accept:
|
22
|
+
# - reject:
|
23
|
+
# - manage_any:
|
24
|
+
# - create_any:
|
25
|
+
# - view_admin_show_any:
|
26
|
+
# - review:
|
27
|
+
# - create_collection_type:
|
5
28
|
#
|
6
29
|
# @note This is intended as a mixin layered over
|
7
30
|
# +Blacklight::AccessControls::Ability+ and +Hydra::AccessControls+. Its
|
@@ -390,10 +413,8 @@ module Hyrax
|
|
390
413
|
# Returns true if the current user is the depositor of the specified work
|
391
414
|
# @param document_id [String] the id of the document.
|
392
415
|
def user_is_depositor?(document_id)
|
393
|
-
Hyrax::
|
394
|
-
|
395
|
-
DepositSearchBuilder.depositor_field => current_user.user_key
|
396
|
-
).any?
|
416
|
+
doc = Hyrax::SolrService.search_by_id(document_id, fl: 'depositor_ssim')
|
417
|
+
current_user.user_key == doc.fetch('depositor_ssim').first
|
397
418
|
end
|
398
419
|
|
399
420
|
def curation_concerns_models
|
@@ -54,6 +54,7 @@ module Hyrax
|
|
54
54
|
attribute :admin_set, Solr::Array, "admin_set_tesim"
|
55
55
|
attribute :member_ids, Solr::Array, "member_ids_ssim"
|
56
56
|
attribute :member_of_collection_ids, Solr::Array, "member_of_collection_ids_ssim"
|
57
|
+
attribute :member_of_collections, Solr::Array, "member_of_collections_ssim"
|
57
58
|
attribute :description, Solr::Array, "description_tesim"
|
58
59
|
attribute :abstract, Solr::Array, "abstract_tesim"
|
59
60
|
attribute :title, Solr::Array, "title_tesim"
|
@@ -12,10 +12,10 @@ class FileDownloadStat < Hyrax::Statistic
|
|
12
12
|
Rails.logger.error("Google Analytics profile has not been established. Unable to fetch statistics.")
|
13
13
|
return []
|
14
14
|
end
|
15
|
-
profile.
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
profile.hyrax__analytics__google__download(sort: 'date',
|
16
|
+
start_date: start_date,
|
17
|
+
end_date: Date.yesterday,
|
18
|
+
limit: 10_000)
|
19
19
|
.for_file(file.id)
|
20
20
|
end
|
21
21
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Hyrax
|
3
|
+
# This class stores the id of the default `Hyrax::AdministrativeSet`. This is
|
4
|
+
# used to populate a cache of the default admin set in Hyrax::Configuration.
|
5
|
+
#
|
6
|
+
# @see Hyrax::Configuration.default_admin_set
|
7
|
+
# @see Hyrax::Configuration.default_admin_set_id
|
8
|
+
# @see Hyrax::Configuration.reset_default_admin_set
|
9
|
+
class DefaultAdministrativeSet < ActiveRecord::Base
|
10
|
+
self.table_name = 'hyrax_default_administrative_set'
|
11
|
+
|
12
|
+
class << self
|
13
|
+
# Set the default admin set id in the first record.
|
14
|
+
# @param default_admin_set_id [String | Valkyrie::ID] id of the new default admin set
|
15
|
+
def update(default_admin_set_id:)
|
16
|
+
validate_id(default_admin_set_id)
|
17
|
+
Hyrax.config.reset_default_admin_set
|
18
|
+
|
19
|
+
# saving default_admin_set_id for the first time
|
20
|
+
return new(default_admin_set_id: default_admin_set_id.to_s).save if count.zero?
|
21
|
+
|
22
|
+
# replacing previously saved default_admin_set_id
|
23
|
+
existing = first
|
24
|
+
existing.default_admin_set_id = default_admin_set_id.to_s
|
25
|
+
existing.save
|
26
|
+
end
|
27
|
+
|
28
|
+
def save_supported?
|
29
|
+
ActiveRecord::Base.connection.table_exists? table_name
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def validate_id(id)
|
35
|
+
# The id is validated prior to updating because a bad default admin set
|
36
|
+
# will cause lots of problems.
|
37
|
+
return true if id.is_a?(String) || id.is_a?(Valkyrie::ID)
|
38
|
+
raise ArgumentError, "default_admin_set_id must be a non-blank String or Valkyrie::ID"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -34,13 +34,40 @@ module Hyrax
|
|
34
34
|
Rails.logger.error("Google Analytics profile has not been established. Unable to fetch statistics.")
|
35
35
|
return []
|
36
36
|
end
|
37
|
-
profile.
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
profile.hyrax__analytics__google__pageviews(sort: 'date',
|
38
|
+
start_date: start_date,
|
39
|
+
end_date: Date.yesterday,
|
40
|
+
limit: 10_000)
|
41
41
|
.for_path(path)
|
42
42
|
end
|
43
43
|
|
44
|
+
def query_works(query)
|
45
|
+
models = Hyrax.config.curation_concerns.map { |m| "\"#{m}\"" }
|
46
|
+
ActiveFedora::SolrService.query("has_model_ssim:(#{models.join(' OR ')})", fl: query, rows: 100_000)
|
47
|
+
end
|
48
|
+
|
49
|
+
def work_types
|
50
|
+
results = query_works("human_readable_type_tesim")
|
51
|
+
results.group_by { |result| result['human_readable_type_tesim'].join('') }.transform_values(&:count)
|
52
|
+
end
|
53
|
+
|
54
|
+
def resource_types
|
55
|
+
results = query_works("resource_type_tesim")
|
56
|
+
resource_types = []
|
57
|
+
results.each do |y|
|
58
|
+
if y["resource_type_tesim"].nil? || (y["resource_type_tesim"] == [""])
|
59
|
+
resource_types.push("Unknown")
|
60
|
+
elsif y["resource_type_tesim"].count > 1
|
61
|
+
y["resource_type_tesim"].each do |t|
|
62
|
+
resource_types.push(t)
|
63
|
+
end
|
64
|
+
else
|
65
|
+
resource_types.push(y["resource_type_tesim"].join(""))
|
66
|
+
end
|
67
|
+
end
|
68
|
+
resource_types.group_by { |rt| rt }.transform_values(&:count)
|
69
|
+
end
|
70
|
+
|
44
71
|
private
|
45
72
|
|
46
73
|
def cached_stats(object, start_date, _method)
|
@@ -3,20 +3,22 @@ module Hyrax
|
|
3
3
|
module Admin
|
4
4
|
class DashboardPresenter
|
5
5
|
# @return [Fixnum] the number of currently registered users
|
6
|
-
def user_count
|
7
|
-
::User.where(guest: false)
|
6
|
+
def user_count(start_date, end_date)
|
7
|
+
::User.where(guest: false)
|
8
|
+
.where({ created_at: start_date.to_date.beginning_of_day..end_date.to_date.end_of_day })
|
9
|
+
.count
|
8
10
|
end
|
9
11
|
|
10
12
|
def repository_objects
|
11
13
|
@repository_objects ||= Admin::RepositoryObjectPresenter.new
|
12
14
|
end
|
13
15
|
|
14
|
-
def repository_growth
|
15
|
-
@repository_growth ||= Admin::RepositoryGrowthPresenter.new
|
16
|
+
def repository_growth(start_date, end_date)
|
17
|
+
@repository_growth ||= Admin::RepositoryGrowthPresenter.new(start_date, end_date)
|
16
18
|
end
|
17
19
|
|
18
|
-
def user_activity
|
19
|
-
@user_activity ||= Admin::UserActivityPresenter.new
|
20
|
+
def user_activity(start_date, end_date)
|
21
|
+
@user_activity ||= Admin::UserActivityPresenter.new(start_date, end_date)
|
20
22
|
end
|
21
23
|
end
|
22
24
|
end
|
@@ -2,26 +2,31 @@
|
|
2
2
|
module Hyrax
|
3
3
|
module Admin
|
4
4
|
class RepositoryGrowthPresenter
|
5
|
-
def initialize
|
6
|
-
@x_min =
|
5
|
+
def initialize(start_date, end_date)
|
6
|
+
@x_min = start_date
|
7
|
+
@x_max = end_date
|
7
8
|
@date_format = ->(x) { x.strftime('%F') }
|
8
9
|
end
|
9
10
|
|
10
11
|
def as_json(*)
|
11
12
|
works.to_a.zip(collections.to_a).map do |e|
|
12
|
-
{ y: e.first.first,
|
13
|
+
{ y: e.first.first, works: e.first.last, collections: e.last.last }
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
16
17
|
private
|
17
18
|
|
18
19
|
def works
|
19
|
-
Hyrax::Statistics::Works::OverTime.new(
|
20
|
+
Hyrax::Statistics::Works::OverTime.new(delta_x: 1,
|
21
|
+
x_min: @x_min,
|
22
|
+
x_max: @x_max,
|
20
23
|
x_output: @date_format).points
|
21
24
|
end
|
22
25
|
|
23
26
|
def collections
|
24
|
-
Hyrax::Statistics::Collections::OverTime.new(
|
27
|
+
Hyrax::Statistics::Collections::OverTime.new(delta_x: 1,
|
28
|
+
x_min: @x_min,
|
29
|
+
x_max: @x_max,
|
25
30
|
x_output: @date_format).points
|
26
31
|
end
|
27
32
|
end
|
@@ -2,28 +2,24 @@
|
|
2
2
|
module Hyrax
|
3
3
|
module Admin
|
4
4
|
class UserActivityPresenter
|
5
|
-
def initialize
|
6
|
-
@x_min =
|
7
|
-
@
|
5
|
+
def initialize(start_date, end_date)
|
6
|
+
@x_min = start_date
|
7
|
+
@x_max = end_date
|
8
|
+
@date_format = ->(x) { x }
|
8
9
|
end
|
9
10
|
|
10
11
|
def as_json(*)
|
11
|
-
new_users.to_a
|
12
|
-
{ y: e.first.first, a: e.first.last, b: e.last.try(:last) }
|
13
|
-
end
|
12
|
+
new_users.to_a
|
14
13
|
end
|
15
14
|
|
16
15
|
private
|
17
16
|
|
18
17
|
def new_users
|
19
|
-
Hyrax::Statistics::Users::OverTime.new(
|
18
|
+
Hyrax::Statistics::Users::OverTime.new(delta_x: 1,
|
19
|
+
x_min: @x_min,
|
20
|
+
x_max: @x_max,
|
20
21
|
x_output: @date_format).points
|
21
22
|
end
|
22
|
-
|
23
|
-
# TODO: using google analytics
|
24
|
-
def returning_users
|
25
|
-
[]
|
26
|
-
end
|
27
23
|
end
|
28
24
|
end
|
29
25
|
end
|
@@ -43,6 +43,10 @@ module Hyrax
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
def analytics_reporting_section?
|
47
|
+
%w[work_reports collection_reports].include?(controller_name)
|
48
|
+
end
|
49
|
+
|
46
50
|
# Draw a collaspable menu section. The passed block should contain <li> items.
|
47
51
|
def collapsable_section(text, id:, icon_class:, open:, &block)
|
48
52
|
CollapsableSectionPresenter.new(view_context: view_context,
|
@@ -10,10 +10,11 @@ module Hyrax
|
|
10
10
|
attr_writer :member_presenter_factory
|
11
11
|
attr_accessor :solr_document, :current_ability, :request
|
12
12
|
|
13
|
-
class_attribute :collection_presenter_class
|
13
|
+
class_attribute :collection_presenter_class, :presenter_factory_class
|
14
14
|
|
15
15
|
# modify this attribute to use an alternate presenter class for the collections
|
16
16
|
self.collection_presenter_class = CollectionPresenter
|
17
|
+
self.presenter_factory_class = MemberPresenterFactory
|
17
18
|
|
18
19
|
# Methods used by blacklight helpers
|
19
20
|
delegate :has?, :first, :fetch, :export_formats, :export_as, to: :solr_document
|
@@ -304,7 +305,9 @@ module Hyrax
|
|
304
305
|
|
305
306
|
def member_presenter_factory
|
306
307
|
@member_presenter_factory ||=
|
307
|
-
|
308
|
+
self.class
|
309
|
+
.presenter_factory_class
|
310
|
+
.new(solr_document, current_ability, request)
|
308
311
|
end
|
309
312
|
|
310
313
|
def graph
|
@@ -66,4 +66,4 @@ module Hyrax
|
|
66
66
|
end
|
67
67
|
```
|
68
68
|
|
69
|
-
There is no point having the other `filter_models` methods apply `:fq`s that we then try to undo or overwrite. In general, directly overwriting the whole `default_processor_chain` or solr parameters like `:fq` is less flexible than appending constraints sufficient for your use case. In particular, you might find that you have overwritten components that implement access controls, thereby making your SearchBuilder less useful and less secure. When in doubt, examine the actual solr queries produced.
|
69
|
+
There is no point having the other `filter_models` methods apply `:fq`s that we then try to undo or overwrite. In general, directly overwriting the whole `default_processor_chain` or solr parameters like `:fq` is less flexible than appending constraints sufficient for your use case. In particular, you might find that you have overwritten components that implement access controls, thereby making your SearchBuilder less useful and less secure. When in doubt, examine the actual solr queries produced.
|
@@ -9,7 +9,7 @@ module Hyrax
|
|
9
9
|
|
10
10
|
# This overrides the models in FilterByType
|
11
11
|
def models
|
12
|
-
[::AdminSet, ::Collection, Hyrax.config.
|
12
|
+
[::AdminSet, ::Collection, Hyrax.config.collection_class].uniq.compact
|
13
13
|
end
|
14
14
|
|
15
15
|
# adds a filter to exclude collections and admin sets created by the
|
@@ -21,6 +21,6 @@ class Hyrax::My::CollectionsSearchBuilder < ::Hyrax::CollectionSearchBuilder
|
|
21
21
|
# This overrides the models in FilterByType
|
22
22
|
# @return [Array<Class>] a list of classes to include
|
23
23
|
def models
|
24
|
-
[::AdminSet, Hyrax::AdministrativeSet, Hyrax.config.
|
24
|
+
[::AdminSet, Hyrax::AdministrativeSet, ::Collection, Hyrax.config.collection_class].uniq.compact
|
25
25
|
end
|
26
26
|
end
|
@@ -13,8 +13,9 @@ module Hyrax
|
|
13
13
|
DEFAULT_ID = 'admin_set/default'
|
14
14
|
DEFAULT_TITLE = ['Default Admin Set'].freeze
|
15
15
|
|
16
|
-
class_attribute :permissions_create_service
|
16
|
+
class_attribute :permissions_create_service, :default_admin_set_persister
|
17
17
|
self.permissions_create_service = Hyrax::Collections::PermissionsCreateService
|
18
|
+
self.default_admin_set_persister = Hyrax::DefaultAdministrativeSet
|
18
19
|
|
19
20
|
class << self
|
20
21
|
# @api public
|
@@ -40,16 +41,15 @@ module Hyrax
|
|
40
41
|
# @see Hyrax::AdministrativeSet
|
41
42
|
# @raise [RuntimeError] if admin set cannot be persisted
|
42
43
|
def find_or_create_default_admin_set
|
43
|
-
|
44
|
-
rescue Valkyrie::Persistence::ObjectNotFoundError
|
45
|
-
create_default_admin_set!
|
44
|
+
find_default_admin_set || create_default_admin_set!
|
46
45
|
end
|
47
46
|
|
48
47
|
# @api public
|
49
|
-
#
|
50
|
-
# @
|
48
|
+
# @param id [#to_s] id of the admin set to check
|
49
|
+
# @return [Boolean] true if the id is for the default admin set; otherwise, false
|
51
50
|
def default_admin_set?(id:)
|
52
|
-
id.
|
51
|
+
return false if id.blank?
|
52
|
+
id.to_s == default_admin_set_id
|
53
53
|
end
|
54
54
|
|
55
55
|
# @api public
|
@@ -88,18 +88,80 @@ module Hyrax
|
|
88
88
|
# TODO: Parameters admin_set_id and title are defined to support .create_default_admin_set
|
89
89
|
# which is deprecated. When it is removed, the parameters will no longer be required.
|
90
90
|
def create_default_admin_set!(admin_set_id: DEFAULT_ID, title: DEFAULT_TITLE)
|
91
|
-
admin_set =
|
92
|
-
new(admin_set: admin_set, creating_user: nil).create!
|
91
|
+
admin_set = create_admin_set(suggested_id: admin_set_id, title: title)
|
92
|
+
admin_set = new(admin_set: admin_set, creating_user: nil, default_admin_set: true).create!
|
93
|
+
default_admin_set_persister.update(default_admin_set_id: admin_set.id) if save_default?
|
94
|
+
admin_set
|
95
|
+
end
|
96
|
+
|
97
|
+
def save_default?
|
98
|
+
default_admin_set_persister.save_supported?
|
99
|
+
end
|
100
|
+
|
101
|
+
# Create an instance of `Hyrax::AdministrativeSet` with the suggested_id if supported.
|
102
|
+
# @return [Hyrax::AdministrativeSet] the new admin set
|
103
|
+
def create_admin_set(suggested_id:, title:)
|
104
|
+
if suggested_id.blank? || Hyrax.config.disable_wings || !Hyrax.metadata_adapter.is_a?(Wings::Valkyrie::MetadataAdapter)
|
105
|
+
# allow persister to assign id
|
106
|
+
Hyrax::AdministrativeSet.new(title: Array.wrap(title))
|
107
|
+
else
|
108
|
+
# use suggested_id
|
109
|
+
Hyrax::AdministrativeSet.new(id: suggested_id, title: Array.wrap(title))
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Find default AdministrativeSet using saved id
|
114
|
+
# @return [Hyrax::AdministrativeSet] the default admin set; nil if id not saved
|
115
|
+
# @raise [RuntimeError] if an admin set with the saved id doesn't exist
|
116
|
+
def find_default_admin_set
|
117
|
+
id = default_admin_set_id
|
118
|
+
return if id.blank?
|
119
|
+
Hyrax.query_service.find_by(id: id)
|
120
|
+
rescue Valkyrie::Persistence::ObjectNotFoundError
|
121
|
+
# The default ID is DEFAULT_ID when saving is not supported. It is ok
|
122
|
+
# for this default id to be known but not found. The admin set will be
|
123
|
+
# created with DEFAULT_ID by find_or_create_default_admin_set.
|
124
|
+
return unless save_default?
|
125
|
+
|
126
|
+
# id is saved in the default_admin_set_persister's table but doesn't exist
|
127
|
+
# NOTE: This is a corrupt state and shouldn't happen. Manual intervention
|
128
|
+
# is required to determine the correct value for the default admin
|
129
|
+
# set id. The saved id either needs to be updated to the correct
|
130
|
+
# value or deleted to allow a new default admin set to be found
|
131
|
+
# (i.e. an admin set with id DEFAULT_ID) or generated.
|
132
|
+
raise "Corrupt default admin set. Persisted admin set with saved default_admin_set_id doesn't exist."
|
133
|
+
end
|
134
|
+
|
135
|
+
# Find default AdministrativeSet using DEFAULT_ID.
|
136
|
+
# @note Use of hardcoded ID is being deprecated as some Valkyrie adapters
|
137
|
+
# do not support hardcoded IDs (e.g. postgres)
|
138
|
+
# @return [Hyrax::AdministrativeSet] the default admin set; nil if not found
|
139
|
+
def find_unsaved_default_admin_set
|
140
|
+
admin_set = Hyrax.query_service.find_by(id: DEFAULT_ID)
|
141
|
+
default_admin_set_persister.update(default_admin_set_id: DEFAULT_ID) if save_default?
|
142
|
+
admin_set
|
143
|
+
rescue Valkyrie::Persistence::ObjectNotFoundError
|
144
|
+
# a default admin set hasn't been created yet
|
145
|
+
end
|
146
|
+
|
147
|
+
# @return [String | nil] the default admin set id; returns nil if not set
|
148
|
+
# @note For general use, it is better to use `Hyrax.config.default_admin_set_id`.
|
149
|
+
def default_admin_set_id
|
150
|
+
return DEFAULT_ID unless save_default?
|
151
|
+
id = default_admin_set_persister.first&.default_admin_set_id
|
152
|
+
id = find_unsaved_default_admin_set&.id&.to_s if id.blank?
|
153
|
+
id
|
93
154
|
end
|
94
155
|
end
|
95
156
|
|
96
157
|
# @param admin_set [Hyrax::AdministrativeSet | AdminSet] the admin set to operate on
|
97
158
|
# @param creating_user [User] the user who created the admin set (if any).
|
98
159
|
# @param workflow_importer [#call] imports the workflow
|
99
|
-
def initialize(admin_set:, creating_user:, workflow_importer: default_workflow_importer)
|
160
|
+
def initialize(admin_set:, creating_user:, workflow_importer: default_workflow_importer, default_admin_set: false)
|
100
161
|
@admin_set = admin_set
|
101
162
|
@creating_user = creating_user
|
102
163
|
@workflow_importer = workflow_importer
|
164
|
+
@default_admin_set = default_admin_set
|
103
165
|
end
|
104
166
|
|
105
167
|
attr_reader :creating_user, :admin_set, :workflow_importer
|
@@ -125,8 +187,8 @@ module Hyrax
|
|
125
187
|
|
126
188
|
private
|
127
189
|
|
128
|
-
def default_admin_set?
|
129
|
-
|
190
|
+
def default_admin_set?
|
191
|
+
@default_admin_set
|
130
192
|
end
|
131
193
|
|
132
194
|
def admin_group_name
|
@@ -144,7 +206,7 @@ module Hyrax
|
|
144
206
|
permission_template = permissions_create_service.create_default(collection: result,
|
145
207
|
creating_user: creating_user)
|
146
208
|
workflow = create_workflows_for(permission_template: permission_template)
|
147
|
-
create_default_access_for(permission_template: permission_template, workflow: workflow) if default_admin_set?
|
209
|
+
create_default_access_for(permission_template: permission_template, workflow: workflow) if default_admin_set?
|
148
210
|
end
|
149
211
|
end
|
150
212
|
end
|
@@ -163,7 +225,7 @@ module Hyrax
|
|
163
225
|
permission_template = permissions_create_service.create_default(collection: admin_set,
|
164
226
|
creating_user: creating_user)
|
165
227
|
workflow = create_workflows_for(permission_template: permission_template)
|
166
|
-
create_default_access_for(permission_template: permission_template, workflow: workflow) if default_admin_set?
|
228
|
+
create_default_access_for(permission_template: permission_template, workflow: workflow) if default_admin_set?
|
167
229
|
end
|
168
230
|
end
|
169
231
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Hyrax
|
3
|
+
module Analytics
|
4
|
+
module Google
|
5
|
+
module Events
|
6
|
+
extend Legato::Model
|
7
|
+
|
8
|
+
metrics :total_events
|
9
|
+
dimensions :event_category, :event_action, :event_label
|
10
|
+
|
11
|
+
# Filter by event id
|
12
|
+
filter :for_id, &->(id) { matches(:eventLabel, id) }
|
13
|
+
|
14
|
+
# Filter by event action
|
15
|
+
filter(:work_view) { |_event_action| matches(:eventAction, 'work-view') }
|
16
|
+
filter(:work_in_collection_view) { |_event_action| matches(:eventAction, 'work-in-collection-view') }
|
17
|
+
filter(:collection_page_view) { |_event_action| matches(:eventAction, 'collection-page-view') }
|
18
|
+
filter(:file_set_download) { |_event_action| matches(:eventAction, 'file-set-download') }
|
19
|
+
filter(:work_in_collection_download) { |_event_action| matches(:eventAction, 'work-in-collection-download') }
|
20
|
+
filter(:file_set_in_work_download) { |_event_action| matches(:eventAction, 'file-set-in-work-download') }
|
21
|
+
filter(:collection_file_download) { |_event_action| matches(:eventAction, 'file-set-in-collection-download') }
|
22
|
+
|
23
|
+
def self.list(profile, start_date, end_date, action)
|
24
|
+
action = action.underscore
|
25
|
+
results = []
|
26
|
+
Events.results(profile,
|
27
|
+
start_date: start_date,
|
28
|
+
end_date: end_date,
|
29
|
+
sort: ['-totalEvents']).send(action).each do |result|
|
30
|
+
results.push([result.eventLabel, result.totalEvents.to_i])
|
31
|
+
end
|
32
|
+
results
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Hyrax
|
3
|
+
module Analytics
|
4
|
+
module Google
|
5
|
+
module EventsDaily
|
6
|
+
extend Legato::Model
|
7
|
+
|
8
|
+
metrics :total_events
|
9
|
+
dimensions :date, :event_category, :event_action
|
10
|
+
|
11
|
+
# Filter by event id
|
12
|
+
filter :for_id, &->(id) { matches(:eventLabel, id) }
|
13
|
+
|
14
|
+
# Filter by event action
|
15
|
+
filter(:work_view) { |_event_action| matches(:eventAction, 'work-view') }
|
16
|
+
filter(:work_in_collection_view) { |_event_action| matches(:eventAction, 'work-in-collection-view') }
|
17
|
+
filter(:collection_page_view) { |_event_action| matches(:eventAction, 'collection-page-view') }
|
18
|
+
filter(:file_set_download) { |_event_action| matches(:eventAction, 'file-set-download') }
|
19
|
+
filter(:work_in_collection_download) { |_event_action| matches(:eventAction, 'work-in-collection-download') }
|
20
|
+
filter(:file_set_in_work_download) { |_event_action| matches(:eventAction, 'file-set-in-work-download') }
|
21
|
+
filter(:collection_file_download) { |_event_action| matches(:eventAction, 'file-set-in-collection-download') }
|
22
|
+
|
23
|
+
# returns a daily number of events for a specific action
|
24
|
+
def self.summary(profile, start_date, end_date, action)
|
25
|
+
action = action.underscore
|
26
|
+
response = EventsDaily.results(profile,
|
27
|
+
start_date: start_date,
|
28
|
+
end_date: end_date).send(action)
|
29
|
+
dates = (start_date.to_date...end_date.to_date)
|
30
|
+
results_array(response, dates)
|
31
|
+
end
|
32
|
+
|
33
|
+
# returns a daily number of events for a specific action
|
34
|
+
def self.by_id(profile, start_date, end_date, id, action)
|
35
|
+
action = action.underscore
|
36
|
+
response = EventsDaily.results(profile,
|
37
|
+
start_date: start_date,
|
38
|
+
end_date: end_date).for_id(id).send(action)
|
39
|
+
dates = (start_date.to_date...end_date.to_date)
|
40
|
+
results_array(response, dates)
|
41
|
+
end
|
42
|
+
|
43
|
+
# def self.pageviews(profile, start_date, end_date, ref)
|
44
|
+
# ref = ref.underscore
|
45
|
+
# response = PageviewsDaily.results(profile,
|
46
|
+
# start_date: start_date,
|
47
|
+
# end_date: end_date).send(ref)
|
48
|
+
# dates = (start_date.to_date...end_date.to_date)
|
49
|
+
# results_array(response, dates)
|
50
|
+
# end
|
51
|
+
|
52
|
+
# takes all the dates in between the date range and generate an array [date, totalEvents]
|
53
|
+
def self.results_array(response, dates)
|
54
|
+
results = []
|
55
|
+
response.to_a.each do |result|
|
56
|
+
results.push([result.date.to_date, result.totalEvents.to_i])
|
57
|
+
end
|
58
|
+
new_results = []
|
59
|
+
dates.each do |date|
|
60
|
+
match = results.detect { |a, _b| a == date }
|
61
|
+
if match
|
62
|
+
new_results.push(match)
|
63
|
+
else
|
64
|
+
new_results.push([date, 0])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
Hyrax::Analytics::Results.new(new_results)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|