curation_concerns 0.12.0.pre1 → 0.12.0.pre2
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/.rubocop.yml +24 -16
- data/Gemfile +0 -4
- data/README.md +14 -0
- data/RELEASING.md +2 -2
- data/Rakefile +2 -0
- data/app/actors/concerns/curation_concerns/manages_embargoes_actor.rb +28 -0
- data/app/actors/curation_concerns/abstract_actor.rb +28 -0
- data/app/actors/curation_concerns/add_to_collection_actor.rb +38 -0
- data/app/actors/curation_concerns/apply_order_actor.rb +24 -0
- data/app/actors/curation_concerns/assign_identifier_actor.rb +7 -0
- data/app/actors/curation_concerns/assign_representative_actor.rb +18 -0
- data/app/actors/curation_concerns/attach_files_actor.rb +39 -0
- data/app/actors/curation_concerns/base_actor.rb +71 -0
- data/app/actors/curation_concerns/embargo_actor.rb +19 -0
- data/app/actors/curation_concerns/file_actor.rb +79 -0
- data/app/actors/curation_concerns/file_set_actor.rb +146 -0
- data/app/actors/curation_concerns/interpret_visibility_actor.rb +123 -0
- data/app/actors/curation_concerns/lease_actor.rb +19 -0
- data/app/actors/curation_concerns/root_actor.rb +17 -0
- data/app/actors/curation_concerns/work_actor_behavior.rb +8 -0
- data/app/assets/javascripts/curation_concerns/batch_select.js +42 -0
- data/app/assets/javascripts/curation_concerns/collections.js +13 -0
- data/app/assets/javascripts/curation_concerns/curation_concerns.js +2 -0
- data/app/assets/stylesheets/curation_concerns/_curation_concerns.scss +0 -3
- data/app/assets/stylesheets/curation_concerns/_modules.scss +1 -1
- data/app/assets/stylesheets/curation_concerns/_positioning.scss +3 -6
- data/app/assets/stylesheets/curation_concerns/_theme.scss +0 -39
- data/app/assets/stylesheets/curation_concerns/_typography.scss +0 -69
- data/app/assets/stylesheets/curation_concerns/modules/classify_work.scss +0 -2
- data/app/assets/stylesheets/curation_concerns/modules/collections.scss +4 -0
- data/app/assets/stylesheets/curation_concerns/modules/forms.scss +0 -4
- data/app/assets/stylesheets/curation_concerns/modules/site_actions.scss +34 -29
- data/app/assets/stylesheets/curation_concerns/modules/site_search.scss +0 -46
- data/app/assets/stylesheets/curation_concerns.scss +4 -0
- data/app/controllers/concerns/curation_concerns/collections_controller_behavior.rb +166 -21
- data/app/controllers/concerns/curation_concerns/embargoes_controller_behavior.rb +1 -1
- data/app/controllers/concerns/curation_concerns/leases_controller_behavior.rb +1 -1
- data/app/controllers/concerns/curation_concerns/selects_collections.rb +65 -0
- data/app/forms/curation_concerns/forms/collection_edit_form.rb +0 -29
- data/app/forms/curation_concerns/forms/work_form.rb +2 -1
- data/app/helpers/batch_select_helper.rb +23 -0
- data/app/helpers/collections_helper.rb +4 -0
- data/app/helpers/curation_concerns/collections_helper.rb +2 -2
- data/app/helpers/curation_concerns/collections_helper_behavior.rb +56 -0
- data/app/helpers/curation_concerns/render_constraints_helper.rb +14 -35
- data/app/helpers/curation_concerns/title_helper.rb +4 -0
- data/app/indexers/curation_concerns/collection_indexer.rb +16 -0
- data/app/indexers/curation_concerns/file_set_indexer.rb +46 -0
- data/app/indexers/curation_concerns/work_indexer.rb +15 -0
- data/app/jobs/audit_job.rb +49 -0
- data/app/jobs/characterize_job.rb +11 -0
- data/app/jobs/create_derivatives_job.rb +21 -0
- data/app/jobs/import_url_job.rb +48 -0
- data/app/jobs/ingest_file_job.rb +30 -0
- data/app/jobs/ingest_local_file_job.rb +20 -0
- data/app/jobs/resolrize_job.rb +7 -0
- data/app/models/checksum_audit_log.rb +20 -0
- data/app/models/collection.rb +6 -0
- data/app/models/concerns/curation_concerns/ability.rb +49 -0
- data/app/models/concerns/curation_concerns/basic_metadata.rb +64 -0
- data/app/models/concerns/curation_concerns/collection.rb +16 -0
- data/app/models/concerns/curation_concerns/collection_behavior.rb +62 -0
- data/app/models/concerns/curation_concerns/file_set/belongs_to_works.rb +47 -0
- data/app/models/concerns/curation_concerns/file_set/derivatives.rb +65 -0
- data/app/models/concerns/curation_concerns/file_set/full_text_indexing.rb +11 -0
- data/app/models/concerns/curation_concerns/file_set/indexing.rb +14 -0
- data/app/models/concerns/curation_concerns/file_set/querying.rb +17 -0
- data/app/models/concerns/curation_concerns/file_set_behavior.rb +36 -0
- data/app/models/concerns/curation_concerns/has_representative.rb +13 -0
- data/app/models/concerns/curation_concerns/human_readable_type.rb +17 -0
- data/app/models/concerns/curation_concerns/naming.rb +17 -0
- data/app/models/concerns/curation_concerns/permissions/readable.rb +18 -0
- data/app/models/concerns/curation_concerns/permissions/writable.rb +34 -0
- data/app/models/concerns/curation_concerns/permissions.rb +7 -0
- data/app/models/concerns/curation_concerns/required_metadata.rb +30 -0
- data/app/models/concerns/curation_concerns/serializers.rb +13 -0
- data/app/models/concerns/curation_concerns/solr_document_behavior.rb +147 -0
- data/app/models/concerns/curation_concerns/user.rb +18 -0
- data/app/models/concerns/curation_concerns/with_file_sets.rb +37 -0
- data/app/models/concerns/curation_concerns/work_behavior.rb +45 -0
- data/app/models/curation_concerns/classify_concern.rb +49 -0
- data/app/models/curation_concerns/quick_classification_query.rb +38 -0
- data/app/models/single_use_link.rb +34 -0
- data/app/models/version_committer.rb +2 -0
- data/app/search_builders/curation_concerns/collection_member_search_builder.rb +1 -1
- data/app/search_builders/curation_concerns/collection_search_builder.rb +33 -0
- data/app/search_builders/curation_concerns/member_search_builder.rb +17 -0
- data/app/services/curation_concerns/derivative_path.rb +49 -0
- data/app/services/curation_concerns/file_set_audit_service.rb +105 -0
- data/app/services/curation_concerns/indexes_thumbnails.rb +30 -0
- data/app/services/curation_concerns/local_file_service.rb +10 -0
- data/app/services/curation_concerns/lock_manager.rb +39 -0
- data/app/services/curation_concerns/lockable.rb +16 -0
- data/app/services/curation_concerns/noid.rb +23 -0
- data/app/services/curation_concerns/persist_derivatives.rb +33 -0
- data/app/services/curation_concerns/persist_directly_contained_output_file_service.rb +26 -0
- data/app/services/curation_concerns/repository_audit_service.rb +7 -0
- data/app/services/curation_concerns/thumbnail_path_service.rb +46 -0
- data/app/services/curation_concerns/time_service.rb +7 -0
- data/app/services/curation_concerns/versioning_service.rb +26 -0
- data/app/validators/has_one_title_validator.rb +8 -0
- data/app/views/batch_select/_add_button.html.erb +3 -0
- data/app/views/batch_select/_check_all.html.erb +4 -0
- data/app/views/batch_select/_tools.html.erb +10 -0
- data/app/views/catalog/_action_menu_partials/_collection.html.erb +3 -3
- data/app/views/catalog/_action_menu_partials/_default.html.erb +1 -1
- data/app/views/catalog/_document_list.html.erb +1 -1
- data/app/views/collections/_bookmark_control.html.erb +2 -0
- data/app/views/collections/_button_create_collection.html.erb +2 -0
- data/app/views/collections/_button_for_creating_empty_collection.html.erb +1 -1
- data/app/views/collections/_button_for_delete_collection.html.erb +4 -0
- data/app/views/collections/_button_for_remove_selected_from_collection.html.erb +8 -0
- data/app/views/collections/_button_for_update_collection.html.erb +4 -0
- data/app/views/collections/_button_remove_from_collection.html.erb +4 -0
- data/app/views/collections/_document_header.html.erb +9 -0
- data/app/views/collections/_edit_actions.html.erb +1 -1
- data/app/views/collections/_edit_descriptions.html.erb +1 -1
- data/app/views/collections/_form.html.erb +2 -2
- data/app/views/collections/_form_for_select_destination_collection.html.erb +21 -0
- data/app/views/collections/_form_to_add_member.html.erb +1 -1
- data/app/views/collections/_index_default.html.erb +2 -0
- data/app/views/collections/_index_header_default.html.erb +2 -0
- data/app/views/collections/_media_display.html.erb +1 -1
- data/app/views/collections/_paginate.html.erb +1 -1
- data/app/views/collections/_paginate_compact.html.erb +1 -0
- data/app/views/collections/_results_pagination.html.erb +9 -0
- data/app/views/collections/_search_collection_dashboard_form.html.erb +1 -1
- data/app/views/collections/_search_form.html.erb +1 -1
- data/app/views/collections/_search_results.html.erb +23 -0
- data/app/views/collections/_show_actions.html.erb +1 -1
- data/app/views/collections/_sort_and_per_page.html.erb +1 -1
- data/app/views/collections/_view_type_group.html.erb +1 -1
- data/app/views/collections/index.html.erb +9 -0
- data/app/views/collections/new.html.erb +3 -0
- data/app/views/curation_concerns/base/_form_permission.html.erb +10 -11
- data/app/views/curation_concerns/base/_form_permission_embargo.html.erb +1 -1
- data/app/views/curation_concerns/base/_form_permission_lease.html.erb +1 -1
- data/app/views/curation_concerns/base/_legally_binding_text.html.erb +7 -7
- data/app/views/curation_concerns/base/_related_files.html.erb +1 -1
- data/app/views/curation_concerns/base/_visibility.html.erb +2 -2
- data/app/views/curation_concerns/file_sets/_actions.html.erb +1 -1
- data/app/views/embargoes/_list_expired_active_embargoes.html.erb +1 -1
- data/app/views/error/single_use_error.html.erb +1 -1
- data/app/views/shared/_add_content.html.erb +17 -15
- data/app/views/shared/_brand_bar.html.erb +19 -10
- data/app/views/shared/_header.html.erb +2 -6
- data/app/views/shared/_my_actions.html.erb +28 -27
- data/app/views/shared/_site_actions.html.erb +5 -1
- data/app/views/shared/_site_search.html.erb +3 -2
- data/app/views/shared/_title_bar.html.erb +7 -16
- data/app/views/welcome/index.html.erb +2 -2
- data/config/locales/curation_concerns.en.yml +25 -1
- data/curation_concerns.gemspec +21 -5
- data/lib/curation_concerns/collections/accepts_batches.rb +53 -0
- data/lib/curation_concerns/collections/search_service.rb +57 -0
- data/lib/curation_concerns/collections.rb +10 -0
- data/lib/curation_concerns/configuration.rb +167 -0
- data/lib/curation_concerns/engine.rb +22 -1
- data/lib/curation_concerns/messages.rb +68 -0
- data/lib/curation_concerns/models.rb +42 -0
- data/lib/curation_concerns/name.rb +20 -0
- data/lib/curation_concerns/null_logger.rb +10 -0
- data/lib/curation_concerns/rails/routes.rb +1 -3
- data/lib/curation_concerns/version.rb +1 -1
- data/lib/curation_concerns.rb +2 -0
- data/lib/generators/curation_concerns/abstract_migration_generator.rb +31 -0
- data/lib/generators/curation_concerns/clamav_generator.rb +19 -0
- data/lib/generators/curation_concerns/collection_generator.rb +15 -0
- data/lib/generators/curation_concerns/install_generator.rb +1 -2
- data/lib/generators/curation_concerns/models_generator.rb +62 -0
- data/lib/generators/curation_concerns/templates/app/models/collection.rb +6 -0
- data/lib/generators/curation_concerns/templates/app/models/file_set.rb +4 -0
- data/lib/generators/curation_concerns/templates/config/clamav.rb +1 -0
- data/lib/generators/curation_concerns/templates/config/curation_concerns.rb +61 -0
- data/lib/generators/curation_concerns/templates/config/mime_types.rb +6 -0
- data/lib/generators/curation_concerns/templates/config/redis.yml +9 -0
- data/lib/generators/curation_concerns/templates/config/redis_config.rb +29 -0
- data/lib/generators/curation_concerns/templates/config/resque-pool.yml +1 -0
- data/lib/generators/curation_concerns/templates/config/resque_config.rb +6 -0
- data/lib/generators/curation_concerns/templates/curation_concerns.scss +3 -2
- data/lib/generators/curation_concerns/templates/migrations/create_checksum_audit_logs.rb +19 -0
- data/lib/generators/curation_concerns/templates/migrations/create_single_use_links.rb +12 -0
- data/lib/generators/curation_concerns/templates/migrations/create_version_committers.rb +15 -0
- data/lib/tasks/migrate.rake +11 -0
- data/lib/tasks/resque.rake +14 -0
- data/lib/tasks/solr_reindex.rake +8 -0
- data/spec/actors/curation_concerns/file_set_actor_spec.rb +31 -0
- data/spec/controllers/accepts_batches_controller_spec.rb +65 -0
- data/spec/controllers/collections_controller_spec.rb +272 -0
- data/spec/controllers/curation_concerns/collections_controller_spec.rb +1 -2
- data/spec/controllers/selects_collections_controller_spec.rb +109 -0
- data/spec/features/create_work_spec.rb +1 -1
- data/spec/features/work_generator_spec.rb +1 -1
- data/spec/forms/collection_edit_form_spec.rb +2 -9
- data/spec/forms/work_form_spec.rb +5 -0
- data/spec/helpers/collections_helper_spec.rb +129 -0
- data/spec/helpers/curation_concerns/collections_helper_spec.rb +2 -2
- data/spec/helpers/render_constraints_helper_spec.rb +23 -1
- data/spec/lib/curation_concerns/collections/search_service_spec.rb +33 -0
- data/spec/models/collection_spec.rb +165 -0
- data/spec/tasks/rake_spec.rb +1 -1
- data/spec/test_app_templates/lib/generators/test_app_generator.rb +1 -1
- data/spec/views/curation_concerns/base/_form_permission.html.erb_spec.rb +4 -1
- data/spec/views/curation_concerns/file_sets/show.html.erb_spec.rb +1 -0
- data/spec/views/shared/_add_content.html.erb_spec.rb +3 -3
- metadata +341 -24
- data/VERSION +0 -1
- data/app/assets/stylesheets/curation_concerns/_global-variables.scss +0 -5
- data/app/assets/stylesheets/curation_concerns/modules/multi_value_fields.scss +0 -52
- data/app/views/collections/_form_required_information.html.erb +0 -11
- data/tasks/release.rake +0 -93
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
class FileSetAuditService
|
|
3
|
+
attr_reader :file_set
|
|
4
|
+
def initialize(file_set)
|
|
5
|
+
@file_set = file_set
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
NO_RUNS = 999
|
|
9
|
+
|
|
10
|
+
# provides a human readable version of the audit status
|
|
11
|
+
# This may trigger audits to be run if required
|
|
12
|
+
# @param [Hydra::PCDM::File] file the file to get the audit status for, defaults to the original_file.
|
|
13
|
+
def human_readable_audit_status(file = file_set.original_file)
|
|
14
|
+
audit_stat(file)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Check the file by only what is in the audit log.
|
|
18
|
+
# Do not try to access the versions if we do not have access to them.
|
|
19
|
+
# Use this when a file_set is loaded from solr instead of fedora
|
|
20
|
+
def logged_audit_status
|
|
21
|
+
audit_results = ChecksumAuditLog.logs_for(file_set.id, "original_file")
|
|
22
|
+
.collect { |result| result["pass"] }
|
|
23
|
+
|
|
24
|
+
if audit_results.length > 0
|
|
25
|
+
stat_to_string(audit_results.reduce(true) { |sum, value| sum && value })
|
|
26
|
+
else
|
|
27
|
+
'Audits have not yet been run on this file.'
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Audits each version of each file if it hasn't been audited recently
|
|
32
|
+
# Returns the set of most recent audit status for each version of the content file
|
|
33
|
+
# @param [Hash] log container for messages, mapping file ids to status
|
|
34
|
+
def audit(log = {})
|
|
35
|
+
file_set.files.each { |f| log[f.id] = audit_file(f) }
|
|
36
|
+
log
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def stat_to_string(stat)
|
|
42
|
+
case stat
|
|
43
|
+
when 0
|
|
44
|
+
'failing'
|
|
45
|
+
when 1
|
|
46
|
+
'passing'
|
|
47
|
+
else
|
|
48
|
+
fail ArgumentError, "Unknown status `#{stat}'"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Retrieve or generate the audit check for a file (all versions are checked for versioned files)
|
|
53
|
+
# @param [ActiveFedora::File] file to audit
|
|
54
|
+
# @param [Array] log container for messages
|
|
55
|
+
def audit_file(file, log = [])
|
|
56
|
+
versions = file.has_versions? ? file.versions.all : file
|
|
57
|
+
versions.each { |v| log << audit_file_version(file.id, v.uri) }
|
|
58
|
+
log
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Retrieve or generate the audit check for a file and provide a human-readable status message.
|
|
62
|
+
# @param [ActiveFedora::File] file to audit
|
|
63
|
+
def audit_stat(file)
|
|
64
|
+
audit_results = audit_file(file).collect { |result| result['pass'] }
|
|
65
|
+
# check how many non runs we had
|
|
66
|
+
non_runs = audit_results.reduce(0) { |sum, value| value == NO_RUNS ? sum + 1 : sum }
|
|
67
|
+
if non_runs == 0
|
|
68
|
+
result = audit_results.reduce(true) { |sum, value| sum && value }
|
|
69
|
+
stat_to_string(result)
|
|
70
|
+
elsif non_runs < audit_results.length
|
|
71
|
+
result = audit_results.reduce(true) { |sum, value| value == NO_RUNS ? sum : sum && value }
|
|
72
|
+
"Some audits have not been run, but the ones run were #{stat_to_string(result)}."
|
|
73
|
+
else
|
|
74
|
+
'Audits have not yet been run on this file.'
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Retrieve or generate the audit check for a specific version of a file
|
|
79
|
+
# @param [String] file_id used to find the file within its parent object (usually "original_file")
|
|
80
|
+
# @param [String] version_uri the version to be audited (or the file uri for non-versioned files)
|
|
81
|
+
def audit_file_version(file_id, version_uri)
|
|
82
|
+
latest_audit = ChecksumAuditLog.logs_for(file_set.id, file_id).first
|
|
83
|
+
return latest_audit unless needs_audit?(latest_audit)
|
|
84
|
+
AuditJob.perform_later(file_set, file_id, version_uri.to_s)
|
|
85
|
+
latest_audit || ChecksumAuditLog.new(pass: NO_RUNS, file_set_id: file_set.id, file_id: file_id, version: version_uri)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Check if time since the last audit is greater than the maximum days allowed between audits
|
|
89
|
+
# @param [ChecksumAuditLog] latest_audit the most recent audit event
|
|
90
|
+
def needs_audit?(latest_audit)
|
|
91
|
+
return true unless latest_audit
|
|
92
|
+
unless latest_audit.updated_at
|
|
93
|
+
logger.warn "***AUDIT*** problem with audit log! Latest Audit is not nil, but updated_at is not set #{latest_audit}"
|
|
94
|
+
return true
|
|
95
|
+
end
|
|
96
|
+
days_since_last_audit(latest_audit) >= CurationConcerns.config.max_days_between_audits
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Return the number of days since the latest audit event
|
|
100
|
+
# @param [ChecksumAuditLog] latest_audit the most recent audit event
|
|
101
|
+
def days_since_last_audit(latest_audit)
|
|
102
|
+
(DateTime.now - latest_audit.updated_at.to_date).to_i
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
module IndexesThumbnails
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
class_attribute :thumbnail_path_service
|
|
7
|
+
self.thumbnail_path_service = ThumbnailPathService
|
|
8
|
+
class_attribute :thumbnail_field
|
|
9
|
+
self.thumbnail_field = 'thumbnail_path_ss'.freeze
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Adds thumbnail indexing to the solr document
|
|
13
|
+
def generate_solr_document
|
|
14
|
+
super.tap do |solr_doc|
|
|
15
|
+
index_thumbnails(solr_doc)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Write the thumbnail paths into the solr_document
|
|
20
|
+
# @params [Hash] solr_document the solr document to add the field to
|
|
21
|
+
def index_thumbnails(solr_document)
|
|
22
|
+
solr_document[thumbnail_field] = thumbnail_path
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Returns the value for the thumbnail path to put into the solr document
|
|
26
|
+
def thumbnail_path
|
|
27
|
+
self.class.thumbnail_path_service.call(object)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
class LocalFileService
|
|
3
|
+
# @param [String] file_name path to the file
|
|
4
|
+
# @param [Hash] _options
|
|
5
|
+
# @yield [File] opens the file and yields it to the block
|
|
6
|
+
def self.call(file_name, _options)
|
|
7
|
+
yield File.open(file_name)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'redlock'
|
|
2
|
+
module CurationConcerns
|
|
3
|
+
class LockManager
|
|
4
|
+
class UnableToAcquireLockError < StandardError; end
|
|
5
|
+
|
|
6
|
+
attr_reader :client
|
|
7
|
+
|
|
8
|
+
# @param [Fixnum] time_to_live How long to hold the lock in milliseconds
|
|
9
|
+
# @param [Fixnum] retry_count How many times to retry to acquire the lock before raising UnableToAcquireLockError
|
|
10
|
+
# @param [Fixnum] retry_delay Maximum wait time in milliseconds before retrying. Wait time is a random value between 0 and retry_delay.
|
|
11
|
+
def initialize(time_to_live, retry_count, retry_delay)
|
|
12
|
+
@ttl = time_to_live
|
|
13
|
+
@client = Redlock::Client.new([uri], retry_count: retry_count, retry_delay: retry_delay)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Blocks until lock is acquired or timeout.
|
|
17
|
+
def lock(key)
|
|
18
|
+
returned_from_block = nil
|
|
19
|
+
client.lock(key, @ttl) do |locked|
|
|
20
|
+
raise UnableToAcquireLockError unless locked
|
|
21
|
+
returned_from_block = yield
|
|
22
|
+
end
|
|
23
|
+
returned_from_block
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def uri
|
|
29
|
+
@uri ||= begin
|
|
30
|
+
opts = options
|
|
31
|
+
URI("#{opts[:scheme]}://#{opts[:host]}:#{opts[:port]}").to_s
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def options
|
|
36
|
+
::Resque.redis.redis.client.options
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
module Lockable
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
def acquire_lock_for(lock_key, &block)
|
|
6
|
+
lock_manager.lock(lock_key, &block)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def lock_manager
|
|
10
|
+
@lock_manager ||= CurationConcerns::LockManager.new(
|
|
11
|
+
CurationConcerns.config.lock_time_to_live,
|
|
12
|
+
CurationConcerns.config.lock_retry_count,
|
|
13
|
+
CurationConcerns.config.lock_retry_delay)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'active_fedora/noid'
|
|
2
|
+
|
|
3
|
+
module CurationConcerns
|
|
4
|
+
module Noid
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
## This overrides the default behavior, which is to ask Fedora for an id
|
|
8
|
+
# @see ActiveFedora::Persistence.assign_id
|
|
9
|
+
def assign_id
|
|
10
|
+
service.mint if CurationConcerns.config.enable_noids
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_param
|
|
14
|
+
id
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def service
|
|
20
|
+
@service ||= ActiveFedora::Noid::Service.new
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
class PersistDerivatives < Hydra::Derivatives::PersistOutputFileService
|
|
3
|
+
# Persists a derivative to the local file system.
|
|
4
|
+
# This Service conforms to the signature of `Hydra::Derivatives::PersistOutputFileService`.
|
|
5
|
+
# This service is an alternative to the default Hydra::Derivatives::PersistOutputFileService.
|
|
6
|
+
# This service will always update existing and does not do versioning of persisted files.
|
|
7
|
+
#
|
|
8
|
+
# @param [#read] stream the derivative filestream
|
|
9
|
+
# @param [Hash] directives
|
|
10
|
+
# @option directives [String] :url a url to the file destination
|
|
11
|
+
def self.call(stream, directives)
|
|
12
|
+
output_file(directives) do |output|
|
|
13
|
+
IO.copy_stream(stream, output)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Open the output file to write and yield the block to the
|
|
18
|
+
# file. It makes the directories in the path if necessary.
|
|
19
|
+
def self.output_file(directives, &blk)
|
|
20
|
+
# name = derivative_path_factory.derivative_path_for_reference(object, destination_name)
|
|
21
|
+
raise ArgumentError, "No :url was provided in the transcoding directives" unless directives.key?(:url)
|
|
22
|
+
uri = URI(directives.fetch(:url))
|
|
23
|
+
raise ArgumentError, "Must provide a file uri" unless uri.scheme == 'file'
|
|
24
|
+
output_file_dir = File.dirname(uri.path)
|
|
25
|
+
FileUtils.mkdir_p(output_file_dir) unless File.directory?(output_file_dir)
|
|
26
|
+
File.open(uri.path, 'wb', &blk)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.derivative_path_factory
|
|
30
|
+
DerivativePath
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
# This Service is an implementation of the Hydra::Derivatives::PersistOutputFileService
|
|
3
|
+
# It supports directly contained files
|
|
4
|
+
class PersistDirectlyContainedOutputFileService < Hydra::Derivatives::PersistBasicContainedOutputFileService
|
|
5
|
+
# This method conforms to the signature of the .call method on Hydra::Derivatives::PersistOutputFileService
|
|
6
|
+
# * Persists the file within the DirectContainer specified by :container
|
|
7
|
+
#
|
|
8
|
+
# @param [#read] stream the data to be persisted
|
|
9
|
+
# @param [Hash] directives directions which can be used to determine where to persist to.
|
|
10
|
+
# @option directives [String] url URI for the parent object.
|
|
11
|
+
# @option directives [String] container Name of the container association.
|
|
12
|
+
def self.call(stream, directives)
|
|
13
|
+
file = Hydra::Derivatives::IoDecorator.new(stream, new_mime_type(directives.fetch(:format)))
|
|
14
|
+
o_name = determine_original_name(file)
|
|
15
|
+
m_type = determine_mime_type(file)
|
|
16
|
+
uri = URI(directives.fetch(:url))
|
|
17
|
+
raise ArgumentError, "#{uri} is not an http uri" unless uri.scheme == 'http'
|
|
18
|
+
file_set = ActiveFedora::Base.find(ActiveFedora::Base.uri_to_id(uri.to_s))
|
|
19
|
+
remote_file = file_set.send("build_#{directives.fetch(:container)}".to_sym)
|
|
20
|
+
remote_file.content = file
|
|
21
|
+
remote_file.mime_type = m_type
|
|
22
|
+
remote_file.original_name = o_name
|
|
23
|
+
file_set.save
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
class ThumbnailPathService
|
|
3
|
+
class << self
|
|
4
|
+
# @param [Work, FileSet] the object to get the thumbnail for
|
|
5
|
+
# @return [String] a path to the thumbnail
|
|
6
|
+
def call(object)
|
|
7
|
+
return default_image unless object.thumbnail_id
|
|
8
|
+
|
|
9
|
+
thumb = fetch_thumbnail(object)
|
|
10
|
+
return unless thumb
|
|
11
|
+
if thumb.audio?
|
|
12
|
+
audio_image
|
|
13
|
+
elsif thumbnail?(thumb)
|
|
14
|
+
Rails.application.routes.url_helpers.download_path(object.thumbnail_id, file: 'thumbnail')
|
|
15
|
+
else
|
|
16
|
+
default_image
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def fetch_thumbnail(object)
|
|
21
|
+
return object if object.thumbnail_id == object.id
|
|
22
|
+
::FileSet.load_instance_from_solr(object.thumbnail_id)
|
|
23
|
+
rescue ActiveFedora::ObjectNotFoundError
|
|
24
|
+
Rails.logger.error("Couldn't find thumbnail #{object.thumbnail_id} for #{object.id}")
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def default_image
|
|
29
|
+
ActionController::Base.helpers.image_path 'default.png'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def audio_image
|
|
33
|
+
ActionController::Base.helpers.image_path 'audio.png'
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @return true if there a file on disk for this object, otherwise false
|
|
37
|
+
def thumbnail?(thumb)
|
|
38
|
+
File.exist?(thumbnail_filepath(thumb))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def thumbnail_filepath(thumb)
|
|
42
|
+
CurationConcerns::DerivativePath.derivative_path_for_reference(thumb, 'thumbnail')
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
class VersioningService
|
|
3
|
+
# Make a version and record the version committer
|
|
4
|
+
# @param [ActiveFedora::File] content
|
|
5
|
+
# @param [User, String] user
|
|
6
|
+
def self.create(content, user = nil)
|
|
7
|
+
content.create_version
|
|
8
|
+
record_committer(content, user) if user
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# @param [ActiveFedora::File] file
|
|
12
|
+
def self.latest_version_of(file)
|
|
13
|
+
file.versions.last
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Record the version committer of the last version
|
|
17
|
+
# @param [ActiveFedora::File] content
|
|
18
|
+
# @param [User, String] user_key
|
|
19
|
+
def self.record_committer(content, user_key)
|
|
20
|
+
user_key = user_key.user_key if user_key.respond_to?(:user_key)
|
|
21
|
+
version = latest_version_of(content)
|
|
22
|
+
return if version.nil?
|
|
23
|
+
VersionCommitter.create(version_id: version.uri, committer_login: user_key)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<div class="btn-group batch-tools hidden" data-behavior="batch-tools">
|
|
2
|
+
<button class="btn"><i class="icon-cog"></i> Tools</button>
|
|
3
|
+
<button class="btn dropdown-toggle" data-toggle="dropdown">
|
|
4
|
+
<span class="caret"></span>
|
|
5
|
+
</button>
|
|
6
|
+
<ul class="dropdown-menu">
|
|
7
|
+
<li data-behavior="batch-edit-activate" data-state="<%= batch_edit_state %>"><a href="#"><i class=""></i> Batch edit</a></li>
|
|
8
|
+
</ul>
|
|
9
|
+
</div>
|
|
10
|
+
|
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
<ul class="dropdown-menu">
|
|
4
4
|
<% if can? :edit, document %>
|
|
5
5
|
<li>
|
|
6
|
-
<%= link_to [
|
|
6
|
+
<%= link_to [:edit, document], class: 'itemicon itemedit' do %><i class="glyphicon glyphicon-pencil"></i> Edit <%= document.human_readable_type %>
|
|
7
7
|
<% end %>
|
|
8
8
|
</li>
|
|
9
9
|
<li>
|
|
10
10
|
<% if @collection # We're on the view page for @collection. -%>
|
|
11
11
|
<%= button_for_remove_from_collection(document) %>
|
|
12
12
|
<% else %>
|
|
13
|
-
<%= link_to
|
|
14
|
-
confirm: "Deleting a collection from #{
|
|
13
|
+
<%= link_to document, class: 'itemicon itemtrash', title: 'Delete Collection', method: :delete, data: {
|
|
14
|
+
confirm: "Deleting a collection from #{application_name} is permanent. Click OK to delete this collection from #{application_name}, or Cancel to cancel this operation" } do %>
|
|
15
15
|
<i class="glyphicon glyphicon-trash"></i> Delete <%= document.human_readable_type %>
|
|
16
16
|
<% end %>
|
|
17
17
|
<% end %>
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<%= link_to document, class: 'itemicon itemtrash',
|
|
15
15
|
title: "Delete #{document.human_readable_type}", method: :delete,
|
|
16
16
|
data: {
|
|
17
|
-
confirm: "Deleting a #{document.human_readable_type} from #{
|
|
17
|
+
confirm: "Deleting a #{document.human_readable_type} from #{application_name} is permanent. Click OK to delete this #{document.human_readable_type} from #{application_name}, or Cancel to cancel this operation" } do %>
|
|
18
18
|
<i class="glyphicon glyphicon-trash"></i> Delete <%= document.human_readable_type %>
|
|
19
19
|
<% end %>
|
|
20
20
|
<% end %>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<h3 id="document-list-heading" class="sr-only">List of items deposited in <%=
|
|
1
|
+
<h3 id="document-list-heading" class="sr-only">List of items deposited in <%= application_name %> that match your search criteria</h3>
|
|
2
2
|
<ol id="documents" class="container-fluid search-results-list" start="<%= document_counter_with_offset(0) %>" aria-labeled-by="document-list-heading">
|
|
3
3
|
<%= render documents, as: :document %>
|
|
4
4
|
</ol>
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
<div class="collection-empty">
|
|
2
|
-
<%= button_to label,
|
|
2
|
+
<%= button_to label, new_collection_path, method: :get, class: "btn btn-primary collection-add collection-empty", 'data-behavior'=>'hydra-collections', id: 'hydra-collection-add' %>
|
|
3
3
|
</div>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<%# button for deleting a collections %>
|
|
2
|
+
<%# collection -- collection to be deleted %>
|
|
3
|
+
<%= button_to label, collection_path(collection.id), data:{confirm: confirm, behavior: 'hydra-collections'}, method: :delete, class: "btn btn-primary collection-delete", id: 'hydra-collection-add' %>
|
|
4
|
+
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<%# button for removing a batch from a collection %>
|
|
2
|
+
<%# collection -- collection to be updated %>
|
|
3
|
+
<%# label -- button label %>
|
|
4
|
+
<%= form_for collection, url:collection_path(collection.id), :method=>:put do |f| %>
|
|
5
|
+
<%= f.hidden_field :members, :value => "remove" %>
|
|
6
|
+
<%= f.submit label, :class => "btn btn-primary collection-remove-selected submits-batches" %>
|
|
7
|
+
<% end %>
|
|
8
|
+
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<%# button for updating a collections %>
|
|
2
|
+
<%# collection_id -- collection to be updated (use 'collection_replace_id' if you wish the form to be updated by a form value) %>
|
|
3
|
+
<%# label -- button label %>
|
|
4
|
+
<%= button_to label, collection_path(collection_id), :method=>:put, :class=>"btn btn-primary updates-collection submits-batches collection-update", 'data-behavior'=>'hydra-collections', :id=>'hydra-collection-update' %>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<% # header bar for doc items in index view -%>
|
|
2
|
+
<div class="documentHeader clearfix">
|
|
3
|
+
<% # main title container for doc partial view -%>
|
|
4
|
+
<h5 class="index_title"><%= t('blacklight.search.documents.counter', :counter => (document_counter + 1 + @response.params[:start].to_i)) %><%= link_to_document document, :label=>document_show_link_field(document), :counter => (document_counter + 1 + @response.params[:start].to_i) %></h5>
|
|
5
|
+
|
|
6
|
+
<div class="documentFunctions span2">
|
|
7
|
+
<%= button_for_remove_from_collection(@collection, document) %>
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<%# This mimics the file_sets/descriptions partial & re-uses some of its sub-partials %>
|
|
2
2
|
<div id="descriptions_display" class="tab-pane active">
|
|
3
|
-
<%= form_for collection, url:
|
|
3
|
+
<%= form_for collection, url: collection_path, html: {multipart: true, class: 'form-horizontal'} do |f| %>
|
|
4
4
|
<%= hidden_field_tag('redirect_tab', 'descriptions') %>
|
|
5
5
|
<h2 class="non lower">Descriptions <small class="pull-right"><span class="error">*</span> indicates required fields</small> </h2>
|
|
6
6
|
<div class="well">
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<%= simple_form_for
|
|
1
|
+
<%= simple_form_for @form do |f| %>
|
|
2
2
|
|
|
3
3
|
<% if f.error_notification %>
|
|
4
4
|
<div class="alert alert-danger fade in">
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
<div class="col-md-12 form-actions">
|
|
16
16
|
<%= f.submit class: 'btn btn-primary require-contributor-agreement' %>
|
|
17
17
|
<% if @form.persisted? %>
|
|
18
|
-
<%= link_to 'Cancel',
|
|
18
|
+
<%= link_to 'Cancel', collection_path(@form), class: 'btn btn-link' %>
|
|
19
19
|
<% else %>
|
|
20
20
|
<%= link_to 'Cancel', main_app.root_path, class: 'btn btn-link' %>
|
|
21
21
|
<% end %>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<% if user_collections.nil?%>
|
|
2
|
+
<b> Make sure you have included CurationConcerns::SelectsCollections in your controller for this page and
|
|
3
|
+
added a before filter with one of the find_collections variations depending on your access level: find_collections, find_collections_with_read_access, find_collections_with_edit_access
|
|
4
|
+
</b>
|
|
5
|
+
<% elsif user_collections.blank? %>
|
|
6
|
+
<b> You do not have access to any existing collections please create a collection. </b>
|
|
7
|
+
<% else %>
|
|
8
|
+
Please Select your collection to add you files to:
|
|
9
|
+
<%= form_tag(collection_path(@collection), :method => "put") do %>
|
|
10
|
+
<input type="hidden" name="test" value="val" />
|
|
11
|
+
<%= hash_as_hidden_fields({:collection =>{members:"move"}}) %>
|
|
12
|
+
<div class="collection-list">
|
|
13
|
+
<ul>
|
|
14
|
+
<% user_collections.each do |collection| %>
|
|
15
|
+
<li> <%= radio_button_tag(:destination_collection_id, collection.id, false, :class => "collection-selector") %><%= label_tag(:collection, collection.title) %> </li>
|
|
16
|
+
<% end %>
|
|
17
|
+
</ul>
|
|
18
|
+
</div>
|
|
19
|
+
<%= button_to "Move to Selected Collection", collections_path, :method=>:put, :class=>"btn btn-primary collection-update submits-batches", 'data-behavior'=>'hydra-collections', :id=>'hydra-collection-move' %>
|
|
20
|
+
<% end %>
|
|
21
|
+
<% end %>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<% fieldset_class ||= '' %>
|
|
2
2
|
<% select_label_id ||= '' %>
|
|
3
3
|
|
|
4
|
-
<%= form_tag
|
|
4
|
+
<%= form_tag main_app.collections_path, method: :put do %>
|
|
5
5
|
<fieldset class="required <%= fieldset_class %>">
|
|
6
6
|
<%= hidden_field_tag 'collection[members]', 'add' %>
|
|
7
7
|
<%= hidden_field_tag 'batch_document_ids[]', collectible.id %>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<a href="<%=
|
|
1
|
+
<a href="<%= collection_path %>" target="_new"><img src="Other.png" alt="No preview available" width="338" /></a>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<% if @response.total_pages > 1 %>
|
|
2
2
|
<div class="pager">
|
|
3
|
-
<%= paginate @response, outer_window: 2, theme: 'blacklight'
|
|
3
|
+
<%= paginate @response, outer_window: 2, theme: 'blacklight' %>
|
|
4
4
|
<div class="clearfix"></div>
|
|
5
5
|
</div><!-- /pager -->
|
|
6
6
|
<% end %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= paginate paginate_compact, page_entries_info: page_entries_info(paginate_compact), theme: :blacklight_compact %>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<div class="col-md-3 pull-right">
|
|
2
|
-
<%= form_for
|
|
2
|
+
<%= form_for @collection, url: edit_collection_path, method: :get, class: "well form-search" do |f| %>
|
|
3
3
|
|
|
4
4
|
<label class="sr-only">Search Collection <%= @collection.title %></label>
|
|
5
5
|
<div class="input-group">
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<div class="col-md-3 pull-right">
|
|
2
|
-
<%= form_for
|
|
2
|
+
<%= form_for @presenter, method: :get, class: "well form-search" do |f| %>
|
|
3
3
|
|
|
4
4
|
<label class="sr-only">Search Collection <%= @presenter.title %></label>
|
|
5
5
|
<div class="input-group">
|