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,17 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
module Naming
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
module ClassMethods
|
|
6
|
+
# Override of ActiveModel::Model name that allows us to use our custom name class
|
|
7
|
+
def model_name
|
|
8
|
+
@_model_name ||= begin
|
|
9
|
+
namespace = parents.detect do |n|
|
|
10
|
+
n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
|
|
11
|
+
end
|
|
12
|
+
CurationConcerns::Name.new(self, namespace)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
module Permissions
|
|
3
|
+
module Readable
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
def public?
|
|
6
|
+
read_groups.include?('public')
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def registered?
|
|
10
|
+
read_groups.include?('registered')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def private?
|
|
14
|
+
!(public? || registered?)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
module Permissions
|
|
3
|
+
module Writable
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
# we're overriding the permissions= method which is in Hydra::AccessControls::Permissions
|
|
7
|
+
include Hydra::AccessControls::Permissions
|
|
8
|
+
include Hydra::AccessControls::Visibility
|
|
9
|
+
|
|
10
|
+
included do
|
|
11
|
+
validate :paranoid_permissions
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def paranoid_permissions
|
|
15
|
+
valid = true
|
|
16
|
+
paranoid_edit_permissions.each do |validation|
|
|
17
|
+
next unless validation[:condition].call(self)
|
|
18
|
+
errors[validation[:key]] ||= []
|
|
19
|
+
errors[validation[:key]] << validation[:message]
|
|
20
|
+
valid = false
|
|
21
|
+
end
|
|
22
|
+
valid
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def paranoid_edit_permissions
|
|
26
|
+
[
|
|
27
|
+
{ key: :edit_users, message: 'Depositor must have edit access', condition: ->(obj) { !obj.edit_users.include?(obj.depositor) } },
|
|
28
|
+
{ key: :edit_groups, message: 'Public cannot have edit access', condition: ->(obj) { obj.edit_groups.include?('public') } },
|
|
29
|
+
{ key: :edit_groups, message: 'Registered cannot have edit access', condition: ->(obj) { obj.edit_groups.include?('registered') } }
|
|
30
|
+
]
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
module RequiredMetadata
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
property :depositor, predicate: ::RDF::URI.new('http://id.loc.gov/vocabulary/relators/dpt'), multiple: false do |index|
|
|
7
|
+
index.as :symbol, :stored_searchable
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
property :title, predicate: ::RDF::Vocab::DC.title do |index|
|
|
11
|
+
index.as :stored_searchable, :facetable
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# We reserve date_uploaded for the original creation date of the record.
|
|
15
|
+
# For example, when migrating data from a fedora3 repo to fedora4,
|
|
16
|
+
# fedora's system created date will reflect the date when the record
|
|
17
|
+
# was created in fedora4, but the date_uploaded will preserve the
|
|
18
|
+
# original creation date from the old repository.
|
|
19
|
+
property :date_uploaded, predicate: ::RDF::Vocab::DC.dateSubmitted, multiple: false do |index|
|
|
20
|
+
index.type :date
|
|
21
|
+
index.as :stored_sortable
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
property :date_modified, predicate: ::RDF::Vocab::DC.modified, multiple: false do |index|
|
|
25
|
+
index.type :date
|
|
26
|
+
index.as :stored_sortable
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
module SolrDocumentBehavior
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
include Hydra::Works::MimeTypes
|
|
5
|
+
|
|
6
|
+
def title_or_label
|
|
7
|
+
title || label
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_param
|
|
11
|
+
id
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def to_s
|
|
15
|
+
title_or_label
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
# Offer the source (ActiveFedora-based) model to Rails for some of the
|
|
20
|
+
# Rails methods (e.g. link_to).
|
|
21
|
+
# @example
|
|
22
|
+
# link_to '...', SolrDocument(:id => 'bXXXXXX5').new => <a href="/dams_object/bXXXXXX5">...</a>
|
|
23
|
+
def to_model
|
|
24
|
+
@model ||= begin
|
|
25
|
+
m = ActiveFedora::Base.load_instance_from_solr(id, self)
|
|
26
|
+
m.class == ActiveFedora::Base ? self : m
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def collection?
|
|
31
|
+
hydra_model == 'Collection'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Method to return the ActiveFedora model
|
|
35
|
+
def hydra_model
|
|
36
|
+
self[Solrizer.solr_name('active_fedora_model', Solrizer::Descriptor.new(:string, :stored, :indexed))]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def human_readable_type
|
|
40
|
+
Array(self[Solrizer.solr_name('human_readable_type', :stored_searchable)]).first
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def representative_id
|
|
44
|
+
fetch(Solrizer.solr_name('hasRelatedMediaFragment', :symbol), []).first
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Date created is indexed as a string. This allows users to enter values like: 'Circa 1840-1844'
|
|
48
|
+
def date_created
|
|
49
|
+
fetch(Solrizer.solr_name("date_created"), []).first
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def date_modified
|
|
53
|
+
date_field('date_modified')
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def date_uploaded
|
|
57
|
+
date_field('date_uploaded')
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def depositor(default = '')
|
|
61
|
+
val = Array(self[Solrizer.solr_name('depositor')]).first
|
|
62
|
+
val.present? ? val : default
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def title
|
|
66
|
+
Array(self[Solrizer.solr_name('title')]).first
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def description
|
|
70
|
+
Array(self[Solrizer.solr_name('description')]).first
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def label
|
|
74
|
+
Array(self[Solrizer.solr_name('label')]).first
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def file_format
|
|
78
|
+
Array(self[Solrizer.solr_name('file_format')]).first
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def creator
|
|
82
|
+
fetch(Solrizer.solr_name('creator'), [])
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def contributor
|
|
86
|
+
fetch(Solrizer.solr_name('contributor'), [])
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def subject
|
|
90
|
+
fetch(Solrizer.solr_name('subject'), [])
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def publisher
|
|
94
|
+
fetch(Solrizer.solr_name('publisher'), [])
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def language
|
|
98
|
+
fetch(Solrizer.solr_name('language'), [])
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def tags
|
|
102
|
+
fetch(Solrizer.solr_name('tag'), [])
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def embargo_release_date
|
|
106
|
+
self[Hydra.config.permissions.embargo.release_date]
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def lease_expiration_date
|
|
110
|
+
self[Hydra.config.permissions.lease.expiration_date]
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def rights
|
|
114
|
+
self[Solrizer.solr_name('rights')]
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def mime_type
|
|
118
|
+
self[Solrizer.solr_name('mime_type', :stored_sortable)]
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def read_groups
|
|
122
|
+
fetch(Hydra.config.permissions.read.group, [])
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def visibility
|
|
126
|
+
@visibility ||= if read_groups.include? Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_PUBLIC
|
|
127
|
+
Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PUBLIC
|
|
128
|
+
elsif read_groups.include? Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_AUTHENTICATED
|
|
129
|
+
Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_AUTHENTICATED
|
|
130
|
+
else
|
|
131
|
+
Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
private
|
|
136
|
+
|
|
137
|
+
def date_field(field_name)
|
|
138
|
+
field = self[Solrizer.solr_name(field_name, :stored_sortable, type: :date)]
|
|
139
|
+
return unless field.present?
|
|
140
|
+
begin
|
|
141
|
+
Date.parse(field).to_formatted_s(:standard)
|
|
142
|
+
rescue
|
|
143
|
+
Rails.logger.info "Unable to parse date: #{field.first.inspect} for #{self['id']}"
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module CurationConcerns::User
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
included do
|
|
4
|
+
delegate :can?, :cannot?, to: :ability
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
# Redefine this for more intuitive keys in Redis
|
|
8
|
+
def to_param
|
|
9
|
+
# HACK: because rails doesn't like periods in urls.
|
|
10
|
+
user_key.gsub(/\./, '-dot-')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def ability
|
|
16
|
+
@ability ||= ::Ability.new(self)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Copied from Curate
|
|
2
|
+
module CurationConcerns
|
|
3
|
+
module WithFileSets
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
included do
|
|
7
|
+
# The file_sets association and its accessor methods comes from Hydra::Works::AggregatesFileSets
|
|
8
|
+
before_destroy :cleanup_file_sets
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Stopgap unil ActiveFedora ContainerAssociation includes an *_ids accessor.
|
|
12
|
+
# At the moment, this is no more efficient than calling file_sets, but hopefully that will change in the future.
|
|
13
|
+
def file_set_ids
|
|
14
|
+
file_sets.map(&:id)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def cleanup_file_sets
|
|
18
|
+
# Destroy the list source first. This prevents each file_set from attemping to
|
|
19
|
+
# remove itself individually from the work. If hundreds of files are attached,
|
|
20
|
+
# this would take too long.
|
|
21
|
+
|
|
22
|
+
# Get list of member file_sets from Solr
|
|
23
|
+
fs = file_sets
|
|
24
|
+
list_source.destroy
|
|
25
|
+
# Remove Work from Solr after it was removed from Fedora
|
|
26
|
+
ActiveFedora::SolrService.delete(id)
|
|
27
|
+
fs.each(&:destroy)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def copy_visibility_to_files
|
|
31
|
+
file_sets.each do |fs|
|
|
32
|
+
fs.visibility = visibility
|
|
33
|
+
fs.save!
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module CurationConcerns::WorkBehavior
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
include Hydra::Works::WorkBehavior
|
|
5
|
+
include CurationConcerns::HumanReadableType
|
|
6
|
+
include CurationConcerns::Noid
|
|
7
|
+
include CurationConcerns::Permissions
|
|
8
|
+
include CurationConcerns::Serializers
|
|
9
|
+
include Hydra::WithDepositor
|
|
10
|
+
include Solrizer::Common
|
|
11
|
+
include CurationConcerns::HasRepresentative
|
|
12
|
+
include CurationConcerns::WithFileSets
|
|
13
|
+
include CurationConcerns::Naming
|
|
14
|
+
include CurationConcerns::RequiredMetadata
|
|
15
|
+
include Hydra::AccessControls::Embargoable
|
|
16
|
+
include GlobalID::Identification
|
|
17
|
+
|
|
18
|
+
included do
|
|
19
|
+
property :owner, predicate: RDF::URI.new('http://opaquenamespace.org/ns/hydra/owner'), multiple: false
|
|
20
|
+
class_attribute :human_readable_short_description
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
module ClassMethods
|
|
24
|
+
def indexer
|
|
25
|
+
CurationConcerns::WorkIndexer
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# This governs which partial to draw when you render this type of object
|
|
29
|
+
def _to_partial_path #:nodoc:
|
|
30
|
+
@_to_partial_path ||= begin
|
|
31
|
+
element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(name))
|
|
32
|
+
collection = ActiveSupport::Inflector.tableize(name)
|
|
33
|
+
"curation_concerns/#{collection}/#{element}".freeze
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def to_s
|
|
39
|
+
if title.present?
|
|
40
|
+
Array(title).join(' | ')
|
|
41
|
+
else
|
|
42
|
+
'No Title'
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require 'active_attr'
|
|
2
|
+
module CurationConcerns
|
|
3
|
+
class ClassifyConcern
|
|
4
|
+
include ActiveAttr::Model
|
|
5
|
+
attribute :curation_concern_type
|
|
6
|
+
|
|
7
|
+
validates(
|
|
8
|
+
:curation_concern_type,
|
|
9
|
+
presence: true,
|
|
10
|
+
inclusion: { in: ->(record) { record.registered_curation_concern_types } }
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
def all_curation_concern_classes
|
|
14
|
+
registered_curation_concern_types.sort.map { |c| self.class.to_class(c) }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def registered_curation_concern_types
|
|
18
|
+
CurationConcerns.config.registered_curation_concern_types
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def possible_curation_concern_types
|
|
22
|
+
registered_curation_concern_types.collect do |concern|
|
|
23
|
+
[self.class.to_class(concern).human_readable_type, concern]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def curation_concern_class
|
|
28
|
+
if possible_curation_concern_types.detect do |_name, class_name|
|
|
29
|
+
class_name == curation_concern_type
|
|
30
|
+
end
|
|
31
|
+
self.class.to_class(curation_concern_type)
|
|
32
|
+
else
|
|
33
|
+
fail 'Invalid :curation_concern_type'
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @option [String] type name of the model
|
|
38
|
+
# @return [Class] the model class
|
|
39
|
+
def self.to_class(type)
|
|
40
|
+
# TODO: we may want to allow a different (or nil) namespace
|
|
41
|
+
type.camelize.constantize
|
|
42
|
+
# begin
|
|
43
|
+
# "::#{type.camelize}".constantize
|
|
44
|
+
# rescue NameError
|
|
45
|
+
# "CurationConcerns::#{type}".constantize
|
|
46
|
+
# end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
class QuickClassificationQuery
|
|
3
|
+
attr_reader :user
|
|
4
|
+
|
|
5
|
+
# @param [User] user the current user
|
|
6
|
+
# @param [Hash] options
|
|
7
|
+
# @option options [#call] :concern_name_normalizer (ClassifyConcern.to_class) a proc that translates names to classes
|
|
8
|
+
# @option options [Array<String>] :models the options to display, defaults to everything.
|
|
9
|
+
def initialize(user, options = {})
|
|
10
|
+
@user = user
|
|
11
|
+
@concern_name_normalizer = options.fetch(:concern_name_normalizer, ClassifyConcern.method(:to_class))
|
|
12
|
+
@models = options.fetch(:models, CurationConcerns.config.registered_curation_concern_types)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def each(&block)
|
|
16
|
+
authorized_models.each(&block)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @return true if the requested concerns is same as all avaliable concerns
|
|
20
|
+
def all?
|
|
21
|
+
models == CurationConcerns.config.registered_curation_concern_types
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @return [Array] a list of all the requested concerns that the user can create
|
|
25
|
+
def authorized_models
|
|
26
|
+
normalized_model_names.select { |klass| user.can?(:create, klass) }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
attr_reader :concern_name_normalizer, :models
|
|
32
|
+
|
|
33
|
+
# Transform the list of requested model names into a list of class names
|
|
34
|
+
def normalized_model_names
|
|
35
|
+
models.map { |name| concern_name_normalizer.call(name) }
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
class SingleUseLink < ActiveRecord::Base
|
|
2
|
+
validate :expiration_date_cannot_be_in_the_past
|
|
3
|
+
validate :cannot_be_destroyed
|
|
4
|
+
|
|
5
|
+
after_initialize :set_defaults
|
|
6
|
+
|
|
7
|
+
def create_for_path(path)
|
|
8
|
+
self.class.create(itemId: itemId, path: path)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def expired?
|
|
12
|
+
DateTime.now > expires
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def to_param
|
|
16
|
+
downloadKey
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
protected
|
|
20
|
+
|
|
21
|
+
def expiration_date_cannot_be_in_the_past
|
|
22
|
+
errors.add(:expires, "can't be in the past") if expired?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def cannot_be_destroyed
|
|
26
|
+
errors[:base] << "Single Use Link has already been used" if destroyed?
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def set_defaults
|
|
30
|
+
return unless new_record?
|
|
31
|
+
self.expires ||= DateTime.now.advance(hours: 24)
|
|
32
|
+
self.downloadKey ||= (Digest::SHA2.new << rand(1_000_000_000).to_s).to_s
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
class CollectionSearchBuilder < ::SearchBuilder
|
|
3
|
+
# Defines which search_params_logic should be used when searching for Collections
|
|
4
|
+
self.default_processor_chain = [:default_solr_parameters, :add_query_to_solr,
|
|
5
|
+
:add_access_controls_to_solr_params, :add_collection_filter, :some_rows, :sort_by_title]
|
|
6
|
+
|
|
7
|
+
def some_rows(solr_parameters)
|
|
8
|
+
solr_parameters[:rows] = '100'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def add_collection_filter(solr_parameters)
|
|
12
|
+
solr_parameters[:fq] ||= []
|
|
13
|
+
solr_parameters[:fq] << ActiveFedora::SolrQueryBuilder.construct_query_for_rel(has_model: ::Collection.to_class_uri)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Sort results by title if no query was supplied.
|
|
17
|
+
# This overrides the default 'relevance' sort.
|
|
18
|
+
def sort_by_title(solr_parameters)
|
|
19
|
+
return if solr_parameters[:q]
|
|
20
|
+
solr_parameters[:sort] ||= "#{sort_field} asc"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
attr_writer :discovery_perms
|
|
24
|
+
|
|
25
|
+
def discovery_permissions
|
|
26
|
+
@discovery_perms || super
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def sort_field
|
|
30
|
+
Solrizer.solr_name('title', :sortable)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
class MemberSearchBuilder < ::SearchBuilder
|
|
3
|
+
class_attribute :from_field
|
|
4
|
+
self.from_field = 'member_ids_ssim'
|
|
5
|
+
|
|
6
|
+
# Defines which search_params_logic should be used when searching for Collection members
|
|
7
|
+
self.default_processor_chain += [:include_collection_ids]
|
|
8
|
+
|
|
9
|
+
delegate :collection, to: :scope
|
|
10
|
+
|
|
11
|
+
# include filters into the query to only include the collection memebers
|
|
12
|
+
def include_collection_ids(solr_parameters)
|
|
13
|
+
solr_parameters[:fq] ||= []
|
|
14
|
+
solr_parameters[:fq] << "{!join from=#{from_field} to=id}id:#{collection.id}"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
class DerivativePath
|
|
3
|
+
class << self
|
|
4
|
+
# Path on file system where derivative file is stored
|
|
5
|
+
def derivative_path_for_reference(object, destination_name)
|
|
6
|
+
destination_name = destination_name.gsub(/^original_file_/, '')
|
|
7
|
+
derivative_path(object, extension_for(destination_name), destination_name)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# @return [Array<String>] Array of paths to derivatives for this object.
|
|
11
|
+
def derivatives_for_reference(object)
|
|
12
|
+
Dir.glob(root_path(object).join("*")).select do |path|
|
|
13
|
+
path.start_with?(path_prefix(object).to_s)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
# @param [#id] object Object whose ID is used to generate root path
|
|
20
|
+
# @return [String] Returns the root path where derivatives will be generated into.
|
|
21
|
+
def root_path(object)
|
|
22
|
+
Pathname.new(derivative_path(object, "", "")).dirname
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @return <Pathname> Full prefix of the path for object.
|
|
26
|
+
def path_prefix(object)
|
|
27
|
+
Pathname.new(CurationConcerns.config.derivatives_path).join(pair_path(object.id))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def derivative_path(object, extension, destination_name)
|
|
31
|
+
file_name = destination_name + extension
|
|
32
|
+
"#{path_prefix(object)}-#{file_name}"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def pair_path(id)
|
|
36
|
+
id.split('').each_slice(2).map(&:join).join('/')
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def extension_for(destination_name)
|
|
40
|
+
case destination_name
|
|
41
|
+
when 'thumbnail'
|
|
42
|
+
".#{MIME::Types.type_for('jpg').first.extensions.first}"
|
|
43
|
+
else
|
|
44
|
+
".#{destination_name}"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|