curation_concerns-models 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.md +177 -0
- data/README.md +42 -0
- data/Rakefile +1 -0
- data/app/actors/concerns/curation_concerns/manages_embargoes_actor.rb +99 -0
- data/app/actors/curation_concerns/base_actor.rb +90 -0
- data/app/actors/curation_concerns/generic_file_actor.rb +150 -0
- data/app/actors/curation_concerns/work_actor_behavior.rb +88 -0
- data/app/jobs/active_fedora_id_based_job.rb +22 -0
- data/app/jobs/active_fedora_pid_based_job.rb +6 -0
- data/app/jobs/audit_job.rb +58 -0
- data/app/jobs/characterize_job.rb +11 -0
- data/app/jobs/copy_permissions_job.rb +24 -0
- data/app/jobs/create_derivatives_job.rb +15 -0
- data/app/jobs/import_url_job.rb +56 -0
- data/app/jobs/ingest_local_file_job.rb +48 -0
- data/app/jobs/resolrize_job.rb +9 -0
- data/app/models/checksum_audit_log.rb +21 -0
- data/app/models/concerns/curation_concerns/ability.rb +34 -0
- data/app/models/concerns/curation_concerns/basic_metadata.rb +87 -0
- data/app/models/concerns/curation_concerns/collection_behavior.rb +47 -0
- data/app/models/concerns/curation_concerns/generic_file/belongs_to_works.rb +53 -0
- data/app/models/concerns/curation_concerns/generic_file/characterization.rb +89 -0
- data/app/models/concerns/curation_concerns/generic_file/content.rb +8 -0
- data/app/models/concerns/curation_concerns/generic_file/export.rb +343 -0
- data/app/models/concerns/curation_concerns/generic_file/full_text_indexing.rb +12 -0
- data/app/models/concerns/curation_concerns/generic_file/indexing.rb +14 -0
- data/app/models/concerns/curation_concerns/generic_file/versions.rb +16 -0
- data/app/models/concerns/curation_concerns/generic_file.rb +5 -0
- data/app/models/concerns/curation_concerns/generic_file_behavior.rb +44 -0
- data/app/models/concerns/curation_concerns/generic_work_behavior.rb +38 -0
- data/app/models/concerns/curation_concerns/has_representative.rb +14 -0
- data/app/models/concerns/curation_concerns/human_readable_type.rb +23 -0
- data/app/models/concerns/curation_concerns/permissions/readable.rb +19 -0
- data/app/models/concerns/curation_concerns/permissions/writable.rb +75 -0
- data/app/models/concerns/curation_concerns/permissions.rb +7 -0
- data/app/models/concerns/curation_concerns/serializers.rb +15 -0
- data/app/models/concerns/curation_concerns/solr_document_behavior.rb +135 -0
- data/app/models/concerns/curation_concerns/user.rb +65 -0
- data/app/models/concerns/curation_concerns/with_basic_metadata.rb +98 -0
- data/app/models/concerns/curation_concerns/with_generic_files.rb +29 -0
- data/app/models/curation_concerns/classify_concern.rb +47 -0
- data/app/models/curation_concerns/quick_classification_query.rb +31 -0
- data/app/models/datastreams/fits_datastream.rb +148 -0
- data/app/models/version_committer.rb +2 -0
- data/app/services/curation_concerns/characterization_service.rb +71 -0
- data/app/services/curation_concerns/full_text_extraction_service.rb +38 -0
- data/app/services/curation_concerns/generic_file_audit_service.rb +85 -0
- data/app/services/curation_concerns/generic_file_indexing_service.rb +14 -0
- data/app/services/curation_concerns/generic_work_indexing_service.rb +16 -0
- data/app/services/curation_concerns/noid.rb +23 -0
- data/app/services/curation_concerns/repository_audit_service.rb +9 -0
- data/app/services/curation_concerns/versioning_service.rb +27 -0
- data/config/locales/curation_concerns.en.yml +6 -0
- data/curation_concerns-models.gemspec +34 -0
- data/lib/curation_concerns/messages.rb +66 -0
- data/lib/curation_concerns/models/engine.rb +61 -0
- data/lib/curation_concerns/models/resque.rb +36 -0
- data/lib/curation_concerns/models/utils.rb +22 -0
- data/lib/curation_concerns/models/version.rb +5 -0
- data/lib/curation_concerns/models.rb +32 -0
- data/lib/generators/curation_concerns/models/abstract_migration_generator.rb +30 -0
- data/lib/generators/curation_concerns/models/clamav_generator.rb +19 -0
- data/lib/generators/curation_concerns/models/fulltext_generator.rb +28 -0
- data/lib/generators/curation_concerns/models/install_generator.rb +70 -0
- data/lib/generators/curation_concerns/models/templates/app/models/collection.rb +4 -0
- data/lib/generators/curation_concerns/models/templates/app/models/generic_file.rb +4 -0
- data/lib/generators/curation_concerns/models/templates/config/clamav.rb +1 -0
- data/lib/generators/curation_concerns/models/templates/config/curation_concerns.rb +123 -0
- data/lib/generators/curation_concerns/models/templates/config/mime_types.rb +6 -0
- data/lib/generators/curation_concerns/models/templates/config/redis.yml +9 -0
- data/lib/generators/curation_concerns/models/templates/config/redis_config.rb +32 -0
- data/lib/generators/curation_concerns/models/templates/config/resque-pool.yml +1 -0
- data/lib/generators/curation_concerns/models/templates/config/resque_admin.rb +10 -0
- data/lib/generators/curation_concerns/models/templates/config/resque_config.rb +5 -0
- data/lib/generators/curation_concerns/models/templates/migrations/create_checksum_audit_logs.rb +19 -0
- data/lib/generators/curation_concerns/models/templates/migrations/create_version_committers.rb +15 -0
- data/lib/tasks/curation_concerns-models_tasks.rake +75 -0
- data/lib/tasks/migrate.rake +13 -0
- data/lib/tasks/resque.rake +13 -0
- data/lib/tasks/solr_reindex.rake +8 -0
- metadata +282 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
class ActiveFedoraIdBasedJob
|
|
2
|
+
def queue_name
|
|
3
|
+
:id_based
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
attr_accessor :id
|
|
7
|
+
|
|
8
|
+
def initialize(id)
|
|
9
|
+
self.id = id
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def object
|
|
13
|
+
@object ||= ActiveFedora::Base.find(id)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
alias_method :generic_file, :object
|
|
17
|
+
alias_method :generic_file_id, :id
|
|
18
|
+
|
|
19
|
+
def run
|
|
20
|
+
raise RuntimeError, "Define #run in a subclass"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
class AuditJob < ActiveFedoraIdBasedJob
|
|
2
|
+
def queue_name
|
|
3
|
+
:audit
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
attr_accessor :uri, :id, :file_id
|
|
7
|
+
|
|
8
|
+
# URI of the resource to audit.
|
|
9
|
+
# This URI could include the actual resource (e.g. content) and the version to audit:
|
|
10
|
+
# http://localhost:8983/fedora/rest/test/a/b/c/abcxyz/content/fcr:versions/version1
|
|
11
|
+
# but it could also just be:
|
|
12
|
+
# http://localhost:8983/fedora/rest/test/a/b/c/abcxyz/content
|
|
13
|
+
# @param [String] id of the parent object
|
|
14
|
+
# @param [String] file_id used to find the file within its parent object (usually "original_file")
|
|
15
|
+
# @param [String] uri of the specific file/version to be audited
|
|
16
|
+
def initialize(id, file_id, uri)
|
|
17
|
+
super(id)
|
|
18
|
+
self.file_id = file_id
|
|
19
|
+
self.uri = uri
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def run
|
|
23
|
+
fixity_ok = false
|
|
24
|
+
log = run_audit
|
|
25
|
+
fixity_ok = (log.pass == 1)
|
|
26
|
+
unless fixity_ok
|
|
27
|
+
if CurationConcerns.config.respond_to?(:after_audit_failure)
|
|
28
|
+
login = generic_file.depositor
|
|
29
|
+
user = User.find_by_user_key(login)
|
|
30
|
+
CurationConcerns.config.after_audit_failure.call(generic_file, user, log.created_at)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
fixity_ok
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
protected
|
|
37
|
+
|
|
38
|
+
def run_audit
|
|
39
|
+
begin
|
|
40
|
+
fixity_ok = ActiveFedora::FixityService.new(uri).check
|
|
41
|
+
rescue Ldp::NotFound
|
|
42
|
+
error_msg = "resource not found"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
if fixity_ok
|
|
46
|
+
passing = 1
|
|
47
|
+
ChecksumAuditLog.prune_history(id, file_id)
|
|
48
|
+
else
|
|
49
|
+
logger.warn "***AUDIT*** Audit failed for #{uri} #{error_msg}"
|
|
50
|
+
passing = 0
|
|
51
|
+
end
|
|
52
|
+
ChecksumAuditLog.create!(pass: passing, generic_file_id: id, version: uri, file_id: file_id)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def logger
|
|
56
|
+
ActiveFedora::Base.logger
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class CharacterizeJob < ActiveFedoraIdBasedJob
|
|
2
|
+
def queue_name
|
|
3
|
+
:characterize
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def run
|
|
7
|
+
CurationConcerns::CharacterizationService.run(generic_file)
|
|
8
|
+
generic_file.save
|
|
9
|
+
CurationConcerns.queue.push(CreateDerivativesJob.new(generic_file.id))
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
class CopyPermissionsJob
|
|
2
|
+
def queue_name
|
|
3
|
+
:permissions
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
attr_accessor :id
|
|
7
|
+
|
|
8
|
+
def initialize(id)
|
|
9
|
+
self.id = id
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def run
|
|
13
|
+
# work = ActiveFedora::Base.load_instance_from_solr(id)
|
|
14
|
+
work = ActiveFedora::Base.find(id) # Hydra::Works::GenericWork is not compatible with load_instance_from_solr. Using (slower) ActiveFedora::Base.find instead.
|
|
15
|
+
if work.respond_to?(:generic_files)
|
|
16
|
+
work.generic_files.each do |file|
|
|
17
|
+
|
|
18
|
+
work.permissions.each {|perm| file.permissions << Hydra::AccessControls::Permission.new(perm.to_hash)}
|
|
19
|
+
new_permissions = file.permissions.uniq! { |item| item.to_hash}
|
|
20
|
+
file.permissions = new_permissions unless new_permissions.blank?
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class CreateDerivativesJob < ActiveFedoraIdBasedJob
|
|
2
|
+
def queue_name
|
|
3
|
+
:derivatives
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def run
|
|
7
|
+
return unless generic_file.original_file.has_content?
|
|
8
|
+
if generic_file.video?
|
|
9
|
+
return unless CurationConcerns.config.enable_ffmpeg
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
generic_file.create_derivatives
|
|
13
|
+
generic_file.save
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'net/https'
|
|
2
|
+
require 'uri'
|
|
3
|
+
require 'tempfile'
|
|
4
|
+
|
|
5
|
+
class ImportUrlJob < ActiveFedoraIdBasedJob
|
|
6
|
+
|
|
7
|
+
def queue_name
|
|
8
|
+
:import_url
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def run
|
|
12
|
+
user = User.find_by_user_key(generic_file.depositor)
|
|
13
|
+
|
|
14
|
+
Tempfile.open(id.gsub('/', '_')) do |f|
|
|
15
|
+
copy_remote_file(generic_file.import_url, f)
|
|
16
|
+
# attach downloaded file to generic file stubbed out
|
|
17
|
+
if CurationConcerns::GenericFileActor.new(generic_file, user).create_content(f)
|
|
18
|
+
|
|
19
|
+
# send message to user on download success
|
|
20
|
+
if CurationConcerns.config.respond_to?(:after_import_url_success)
|
|
21
|
+
CurationConcerns.config.after_import_url_success.call(generic_file, user)
|
|
22
|
+
end
|
|
23
|
+
else
|
|
24
|
+
|
|
25
|
+
# send message to user on download failure
|
|
26
|
+
if CurationConcerns.config.respond_to?(:after_import_url_failure)
|
|
27
|
+
CurationConcerns.config.after_import_url_failure.call(generic_file, user)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def copy_remote_file(import_url, f)
|
|
34
|
+
f.binmode
|
|
35
|
+
# download file from url
|
|
36
|
+
uri = URI(generic_file.import_url)
|
|
37
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
38
|
+
http.use_ssl = uri.scheme == "https" # enable SSL/TLS
|
|
39
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
40
|
+
mime_type = nil
|
|
41
|
+
|
|
42
|
+
http.start do
|
|
43
|
+
http.request_get(uri.request_uri) do |resp|
|
|
44
|
+
mime_type = resp.content_type
|
|
45
|
+
resp.read_body do |segment|
|
|
46
|
+
f.write(segment)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
f.rewind
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def job_user
|
|
54
|
+
User.batchuser
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
class IngestLocalFileJob
|
|
2
|
+
attr_accessor :directory, :filename, :user_key, :generic_file_id
|
|
3
|
+
|
|
4
|
+
def queue_name
|
|
5
|
+
:ingest
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def initialize(generic_file_id, directory, filename, user_key)
|
|
9
|
+
self.generic_file_id = generic_file_id
|
|
10
|
+
self.directory = directory
|
|
11
|
+
self.filename = filename
|
|
12
|
+
self.user_key = user_key
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def run
|
|
16
|
+
user = User.find_by_user_key(user_key)
|
|
17
|
+
raise "Unable to find user for #{user_key}" unless user
|
|
18
|
+
generic_file = GenericFile.find(generic_file_id)
|
|
19
|
+
generic_file.label ||= filename
|
|
20
|
+
path = File.join(directory, filename)
|
|
21
|
+
|
|
22
|
+
actor = CurationConcerns::GenericFileActor.new(generic_file, user)
|
|
23
|
+
|
|
24
|
+
if actor.create_content(File.open(path))
|
|
25
|
+
FileUtils.rm(path)
|
|
26
|
+
|
|
27
|
+
# send message to user on import success
|
|
28
|
+
if CurationConcerns.config.respond_to?(:after_import_local_file_success)
|
|
29
|
+
CurationConcerns.config.after_import_local_file_success.call(generic_file, user, filename)
|
|
30
|
+
end
|
|
31
|
+
else
|
|
32
|
+
|
|
33
|
+
# send message to user on import failure
|
|
34
|
+
if CurationConcerns.config.respond_to?(:after_import_local_file_failure)
|
|
35
|
+
CurationConcerns.config.after_import_local_file_failure.call(generic_file, user, filename)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def job_user
|
|
41
|
+
User.batchuser
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def mime_type(file_name)
|
|
45
|
+
mime_types = MIME::Types.of(file_name)
|
|
46
|
+
mime_types.empty? ? "application/octet-stream" : mime_types.first.content_type
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class ChecksumAuditLog < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
def self.get_audit_log(id, path, version_uri)
|
|
4
|
+
ChecksumAuditLog.find_or_create_by(generic_file_id: id, file_id: path, version: version_uri)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
# Check to see if there are previous passing logs that we can delete
|
|
8
|
+
# we want to keep the first passing event after a failure, the most current passing event,
|
|
9
|
+
# and all failures so that this table doesn't grow too large
|
|
10
|
+
# Simple way (a little naieve): if the last 2 were passing, delete the first one
|
|
11
|
+
def self.prune_history(id, path)
|
|
12
|
+
list = logs_for(id, path).limit(2)
|
|
13
|
+
if list.size > 1 && (list[0].pass == 1) && (list[1].pass == 1)
|
|
14
|
+
list[0].destroy
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.logs_for(id, path)
|
|
19
|
+
ChecksumAuditLog.where(generic_file_id: id, file_id: path).order('created_at desc, id desc')
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
module Ability
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
included do
|
|
5
|
+
self.ability_logic += [:curation_concerns_permissions]
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def curation_concerns_permissions
|
|
9
|
+
|
|
10
|
+
unless current_user.new_record?
|
|
11
|
+
can :create, CurationConcerns::ClassifyConcern
|
|
12
|
+
# TODO: Shouldn't this be in `everyone_can_create_curation_concerns` ?
|
|
13
|
+
can :create, ::GenericFile
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
if user_groups.include? 'admin'
|
|
17
|
+
can [:create, :discover, :show, :read, :edit, :update, :destroy], :all
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
can :collect, :all
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Add this to your ability_logic if you want all logged in users to be able
|
|
25
|
+
# to submit content
|
|
26
|
+
def everyone_can_create_curation_concerns
|
|
27
|
+
unless current_user.new_record?
|
|
28
|
+
can :create, [ CurationConcerns.configuration.curation_concerns ]
|
|
29
|
+
can :create, ::Collection
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
module BasicMetadata
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
|
|
7
|
+
property :label, predicate: ActiveFedora::RDF::Fcrepo::Model.downloadFilename, multiple: false
|
|
8
|
+
|
|
9
|
+
property :depositor, predicate: ::RDF::URI.new("http://id.loc.gov/vocabulary/relators/dpt"), multiple: false do |index|
|
|
10
|
+
index.as :symbol, :stored_searchable
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
property :relative_path, predicate: ::RDF::URI.new('http://scholarsphere.psu.edu/ns#relativePath'), multiple: false
|
|
14
|
+
|
|
15
|
+
property :import_url, predicate: ::RDF::URI.new('http://scholarsphere.psu.edu/ns#importUrl'), multiple: false do |index|
|
|
16
|
+
index.as :symbol
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
property :part_of, predicate: ::RDF::DC.isPartOf
|
|
20
|
+
property :resource_type, predicate: ::RDF::DC.type do |index|
|
|
21
|
+
index.as :stored_searchable, :facetable
|
|
22
|
+
end
|
|
23
|
+
property :title, predicate: ::RDF::DC.title do |index|
|
|
24
|
+
index.as :stored_searchable, :facetable
|
|
25
|
+
end
|
|
26
|
+
property :creator, predicate: ::RDF::DC.creator do |index|
|
|
27
|
+
index.as :stored_searchable, :facetable
|
|
28
|
+
end
|
|
29
|
+
property :contributor, predicate: ::RDF::DC.contributor do |index|
|
|
30
|
+
index.as :stored_searchable, :facetable
|
|
31
|
+
end
|
|
32
|
+
property :description, predicate: ::RDF::DC.description do |index|
|
|
33
|
+
index.type :text
|
|
34
|
+
index.as :stored_searchable
|
|
35
|
+
end
|
|
36
|
+
property :tag, predicate: ::RDF::DC.relation do |index|
|
|
37
|
+
index.as :stored_searchable, :facetable
|
|
38
|
+
end
|
|
39
|
+
property :rights, predicate: ::RDF::DC.rights do |index|
|
|
40
|
+
index.as :stored_searchable
|
|
41
|
+
end
|
|
42
|
+
property :publisher, predicate: ::RDF::DC.publisher do |index|
|
|
43
|
+
index.as :stored_searchable, :facetable
|
|
44
|
+
end
|
|
45
|
+
property :date_created, predicate: ::RDF::DC.created do |index|
|
|
46
|
+
index.as :stored_searchable
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# We reserve date_uploaded for the original creation date of the record.
|
|
50
|
+
# For example, when migrating data from a fedora3 repo to fedora4,
|
|
51
|
+
# fedora's system created date will reflect the date when the record
|
|
52
|
+
# was created in fedora4, but the date_uploaded will preserve the
|
|
53
|
+
# original creation date from the old repository.
|
|
54
|
+
property :date_uploaded, predicate: ::RDF::DC.dateSubmitted, multiple: false do |index|
|
|
55
|
+
index.type :date
|
|
56
|
+
index.as :stored_sortable
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
property :date_modified, predicate: ::RDF::DC.modified, multiple: false do |index|
|
|
60
|
+
index.type :date
|
|
61
|
+
index.as :stored_sortable
|
|
62
|
+
end
|
|
63
|
+
property :subject, predicate: ::RDF::DC.subject do |index|
|
|
64
|
+
index.as :stored_searchable, :facetable
|
|
65
|
+
end
|
|
66
|
+
property :language, predicate: ::RDF::DC.language do |index|
|
|
67
|
+
index.as :stored_searchable, :facetable
|
|
68
|
+
end
|
|
69
|
+
property :identifier, predicate: ::RDF::DC.identifier do |index|
|
|
70
|
+
index.as :stored_searchable
|
|
71
|
+
end
|
|
72
|
+
property :based_near, predicate: ::RDF::FOAF.based_near do |index|
|
|
73
|
+
index.as :stored_searchable, :facetable
|
|
74
|
+
end
|
|
75
|
+
property :related_url, predicate: ::RDF::RDFS.seeAlso do |index|
|
|
76
|
+
index.as :stored_searchable
|
|
77
|
+
end
|
|
78
|
+
property :bibliographic_citation, predicate: ::RDF::DC.bibliographicCitation do |index|
|
|
79
|
+
index.as :stored_searchable
|
|
80
|
+
end
|
|
81
|
+
property :source, predicate: ::RDF::DC.source do |index|
|
|
82
|
+
index.as :stored_searchable
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
module CollectionBehavior
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
include Hydra::AccessControls::WithAccessRight
|
|
6
|
+
include Hydra::Collection
|
|
7
|
+
include CurationConcerns::Noid
|
|
8
|
+
include CurationConcerns::HumanReadableType
|
|
9
|
+
include CurationConcerns::HasRepresentative
|
|
10
|
+
include CurationConcerns::Permissions
|
|
11
|
+
|
|
12
|
+
included do
|
|
13
|
+
validates :title, presence: true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def add_member(collectible)
|
|
17
|
+
if can_add_to_members?(collectible)
|
|
18
|
+
self.members << collectible
|
|
19
|
+
save
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def to_s
|
|
24
|
+
title.present? ? title : "No Title"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def bytes
|
|
28
|
+
members.reduce(0) { |sum, gf| sum + gf.content.size.to_i }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def to_solr(solr_doc={})
|
|
32
|
+
super(solr_doc).tap do |solr_doc|
|
|
33
|
+
Solrizer.set_field(solr_doc, 'generic_type', human_readable_type, :facetable)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def can_be_member_of_collection?(collection)
|
|
38
|
+
collection == self ? false : true
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def can_add_to_members?(collectible)
|
|
44
|
+
collectible.try(:can_be_member_of_collection?, self)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
module GenericFile
|
|
3
|
+
module BelongsToWorks
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
included do
|
|
7
|
+
before_destroy :remove_representative_relationship
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def generic_works
|
|
11
|
+
self.parent_objects # parent_objects is provided by Hydra::PCDM::ObjectBehavior
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def generic_work_ids
|
|
15
|
+
generic_works.map { |work| work.id }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Returns the first parent object
|
|
19
|
+
# This is a hack to handle things like GenericFiles inheriting access controls from their parent. (see CurationConcerns::ParentContainer in app/controllers/concerns/curation_concers/parent_container.rb)
|
|
20
|
+
def parent
|
|
21
|
+
self.parent_objects.first
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Returns the id of first parent object
|
|
25
|
+
# This is a hack to handle things like GenericFiles inheriting access controls from their parent. (see CurationConcerns::ParentContainer in app/controllers/concerns/curation_concers/parent_container.rb)
|
|
26
|
+
def parent_id
|
|
27
|
+
parent.id
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Files with sibling relationships
|
|
31
|
+
# Returns all GenericFiles aggregated by any of the GenericWorks that aggregate the current object
|
|
32
|
+
def related_files
|
|
33
|
+
generic_works = self.generic_works
|
|
34
|
+
return [] if generic_works.empty?
|
|
35
|
+
generic_works.flat_map {|work| work.generic_files.select {|generic_file| generic_file.id != self.id } }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# If any parent works are pointing at this object as their representative, remove that pointer.
|
|
39
|
+
def remove_representative_relationship
|
|
40
|
+
generic_works = self.generic_works
|
|
41
|
+
return if generic_works.empty?
|
|
42
|
+
generic_works.each do |work|
|
|
43
|
+
if work.representative == self.id
|
|
44
|
+
work.representative = nil
|
|
45
|
+
work.save
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
module GenericFile
|
|
3
|
+
module Characterization
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
included do
|
|
6
|
+
contains "characterization", class_name: 'FitsDatastream'
|
|
7
|
+
property :mime_type, delegate_to: 'characterization', multiple: false do |index|
|
|
8
|
+
index.as :stored_searchable
|
|
9
|
+
end
|
|
10
|
+
property :format_label, delegate_to: 'characterization'
|
|
11
|
+
property :file_size, delegate_to: 'characterization'
|
|
12
|
+
property :last_modified, delegate_to: 'characterization'
|
|
13
|
+
property :filename, delegate_to: 'characterization'
|
|
14
|
+
property :original_checksum, delegate_to: 'characterization'
|
|
15
|
+
property :rights_basis, delegate_to: 'characterization'
|
|
16
|
+
property :copyright_basis, delegate_to: 'characterization'
|
|
17
|
+
property :copyright_note, delegate_to: 'characterization'
|
|
18
|
+
property :well_formed, delegate_to: 'characterization'
|
|
19
|
+
property :valid, delegate_to: 'characterization'
|
|
20
|
+
property :status_message, delegate_to: 'characterization'
|
|
21
|
+
property :file_title, delegate_to: 'characterization'
|
|
22
|
+
property :file_author, delegate_to: 'characterization'
|
|
23
|
+
property :page_count, delegate_to: 'characterization'
|
|
24
|
+
property :file_language, delegate_to: 'characterization'
|
|
25
|
+
property :word_count, delegate_to: 'characterization'
|
|
26
|
+
property :character_count, delegate_to: 'characterization'
|
|
27
|
+
property :paragraph_count, delegate_to: 'characterization'
|
|
28
|
+
property :line_count, delegate_to: 'characterization'
|
|
29
|
+
property :table_count, delegate_to: 'characterization'
|
|
30
|
+
property :graphics_count, delegate_to: 'characterization'
|
|
31
|
+
property :byte_order, delegate_to: 'characterization'
|
|
32
|
+
property :compression, delegate_to: 'characterization'
|
|
33
|
+
property :color_space, delegate_to: 'characterization'
|
|
34
|
+
property :profile_name, delegate_to: 'characterization'
|
|
35
|
+
property :profile_version, delegate_to: 'characterization'
|
|
36
|
+
property :orientation, delegate_to: 'characterization'
|
|
37
|
+
property :color_map, delegate_to: 'characterization'
|
|
38
|
+
property :image_producer, delegate_to: 'characterization'
|
|
39
|
+
property :capture_device, delegate_to: 'characterization'
|
|
40
|
+
property :scanning_software, delegate_to: 'characterization'
|
|
41
|
+
property :exif_version, delegate_to: 'characterization'
|
|
42
|
+
property :gps_timestamp, delegate_to: 'characterization'
|
|
43
|
+
property :latitude, delegate_to: 'characterization'
|
|
44
|
+
property :longitude, delegate_to: 'characterization'
|
|
45
|
+
property :character_set, delegate_to: 'characterization'
|
|
46
|
+
property :markup_basis, delegate_to: 'characterization'
|
|
47
|
+
property :markup_language, delegate_to: 'characterization'
|
|
48
|
+
property :bit_depth, delegate_to: 'characterization'
|
|
49
|
+
property :channels, delegate_to: 'characterization'
|
|
50
|
+
property :data_format, delegate_to: 'characterization'
|
|
51
|
+
property :offset, delegate_to: 'characterization'
|
|
52
|
+
property :frame_rate, delegate_to: 'characterization'
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def width
|
|
57
|
+
characterization.width.blank? ? characterization.video_width : characterization.width
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def height
|
|
61
|
+
characterization.height.blank? ? characterization.video_height : characterization.height
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def duration
|
|
65
|
+
characterization.duration.blank? ? characterization.video_duration : characterization.duration
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def sample_rate
|
|
69
|
+
characterization.sample_rate.blank? ? characterization.video_sample_rate : characterization.sample_rate
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def characterization_terms
|
|
73
|
+
h = {}
|
|
74
|
+
self.characterization.class.terminology.terms.each_pair do |k, v|
|
|
75
|
+
next unless v.respond_to? :proxied_term
|
|
76
|
+
term = v.proxied_term
|
|
77
|
+
begin
|
|
78
|
+
value = self.send(term.name)
|
|
79
|
+
h[term.name] = value unless value.empty?
|
|
80
|
+
rescue NoMethodError
|
|
81
|
+
next
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
h
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|