curation_concerns-models 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/Rakefile +1 -1
- data/app/actors/concerns/curation_concerns/manages_embargoes_actor.rb +11 -19
- data/app/actors/curation_concerns/base_actor.rb +41 -45
- data/app/actors/curation_concerns/embargo_actor.rb +19 -0
- data/app/actors/curation_concerns/file_set_actor.rb +200 -0
- data/app/actors/curation_concerns/lease_actor.rb +19 -0
- data/app/actors/curation_concerns/work_actor_behavior.rb +55 -58
- data/app/indexers/curation_concerns/collection_indexer.rb +10 -0
- data/app/indexers/curation_concerns/file_set_indexing_service.rb +24 -0
- data/app/{services/curation_concerns/generic_work_indexing_service.rb → indexers/curation_concerns/work_indexing_service.rb} +6 -6
- data/app/jobs/active_fedora_id_based_job.rb +5 -12
- data/app/jobs/audit_job.rb +11 -17
- data/app/jobs/characterize_job.rb +8 -7
- data/app/jobs/create_derivatives_job.rb +8 -11
- data/app/jobs/import_url_job.rb +12 -25
- data/app/jobs/ingest_file_job.rb +16 -0
- data/app/jobs/ingest_local_file_job.rb +14 -35
- data/app/jobs/resolrize_job.rb +3 -5
- data/app/jobs/upload_set_update_job.rb +68 -0
- data/app/models/checksum_audit_log.rb +2 -3
- data/app/models/concerns/curation_concerns/ability.rb +18 -10
- data/app/models/concerns/curation_concerns/basic_metadata.rb +1 -3
- data/app/models/concerns/curation_concerns/collection_behavior.rb +13 -14
- data/app/models/concerns/curation_concerns/file_set/belongs_to_upload_sets.rb +15 -0
- data/app/models/concerns/curation_concerns/{generic_file → file_set}/belongs_to_works.rb +8 -14
- data/app/models/concerns/curation_concerns/file_set/derivatives.rb +54 -0
- data/app/models/concerns/curation_concerns/{generic_file → file_set}/full_text_indexing.rb +1 -2
- data/app/models/concerns/curation_concerns/{generic_file → file_set}/indexing.rb +2 -2
- data/app/models/concerns/curation_concerns/{generic_file → file_set}/versions.rb +2 -3
- data/app/models/concerns/curation_concerns/file_set_behavior.rb +36 -0
- data/app/models/concerns/curation_concerns/generic_file.rb +1 -1
- data/app/models/concerns/curation_concerns/has_representative.rb +6 -7
- data/app/models/concerns/curation_concerns/human_readable_type.rb +5 -7
- data/app/models/concerns/curation_concerns/permissions.rb +2 -2
- data/app/models/concerns/curation_concerns/permissions/readable.rb +0 -1
- data/app/models/concerns/curation_concerns/permissions/writable.rb +10 -51
- data/app/models/concerns/curation_concerns/serializers.rb +3 -5
- data/app/models/concerns/curation_concerns/solr_document_behavior.rb +37 -40
- data/app/models/concerns/curation_concerns/upload_set_behavior.rb +38 -0
- data/app/models/concerns/curation_concerns/user.rb +4 -51
- data/app/models/concerns/curation_concerns/with_file_sets.rb +28 -0
- data/app/models/concerns/curation_concerns/{generic_work_behavior.rb → work_behavior.rb} +12 -6
- data/app/models/curation_concerns/classify_concern.rb +7 -7
- data/app/models/curation_concerns/quick_classification_query.rb +6 -7
- data/app/models/single_use_link.rb +34 -0
- data/app/models/upload_set.rb +3 -0
- data/app/services/curation_concerns/derivative_path.rb +32 -0
- data/app/services/curation_concerns/{generic_file_audit_service.rb → file_set_audit_service.rb} +17 -18
- data/app/services/curation_concerns/indexes_thumbnails.rb +14 -0
- data/app/services/curation_concerns/local_file_service.rb +10 -0
- data/app/services/curation_concerns/lock_manager.rb +40 -0
- data/app/services/curation_concerns/noid.rb +1 -1
- 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 +1 -3
- 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 +11 -12
- data/curation_concerns-models.gemspec +6 -6
- data/lib/curation_concerns/configuration.rb +154 -0
- data/lib/curation_concerns/messages.rb +26 -26
- data/lib/curation_concerns/models.rb +5 -14
- data/lib/curation_concerns/models/engine.rb +0 -30
- data/lib/curation_concerns/models/utils.rb +4 -4
- data/lib/curation_concerns/models/version.rb +1 -1
- data/lib/generators/curation_concerns/models/abstract_migration_generator.rb +8 -7
- data/lib/generators/curation_concerns/models/clamav_generator.rb +3 -3
- data/lib/generators/curation_concerns/models/install_generator.rb +13 -20
- data/lib/generators/curation_concerns/models/templates/app/models/file_set.rb +4 -0
- data/lib/generators/curation_concerns/models/templates/config/clamav.rb +1 -1
- data/lib/generators/curation_concerns/models/templates/config/curation_concerns.rb +52 -65
- data/lib/generators/curation_concerns/models/templates/config/redis_config.rb +13 -17
- data/lib/generators/curation_concerns/models/templates/config/resque_config.rb +2 -1
- data/lib/generators/curation_concerns/models/templates/migrations/create_checksum_audit_logs.rb +3 -3
- data/lib/generators/curation_concerns/models/templates/migrations/create_single_use_links.rb +12 -0
- data/lib/tasks/curation_concerns-models_tasks.rake +4 -62
- data/lib/tasks/migrate.rake +1 -1
- data/lib/tasks/resque.rake +1 -0
- data/lib/tasks/solr_reindex.rake +1 -1
- metadata +59 -52
- data/app/actors/curation_concerns/generic_file_actor.rb +0 -150
- data/app/jobs/active_fedora_pid_based_job.rb +0 -6
- data/app/jobs/copy_permissions_job.rb +0 -24
- data/app/models/concerns/curation_concerns/generic_file/characterization.rb +0 -89
- data/app/models/concerns/curation_concerns/generic_file/content.rb +0 -8
- data/app/models/concerns/curation_concerns/generic_file/export.rb +0 -343
- data/app/models/concerns/curation_concerns/generic_file_behavior.rb +0 -44
- data/app/models/concerns/curation_concerns/with_basic_metadata.rb +0 -98
- data/app/models/concerns/curation_concerns/with_generic_files.rb +0 -29
- data/app/models/datastreams/fits_datastream.rb +0 -148
- data/app/services/curation_concerns/characterization_service.rb +0 -71
- data/app/services/curation_concerns/full_text_extraction_service.rb +0 -38
- data/app/services/curation_concerns/generic_file_indexing_service.rb +0 -14
- data/lib/curation_concerns/models/resque.rb +0 -36
- data/lib/generators/curation_concerns/models/fulltext_generator.rb +0 -28
- data/lib/generators/curation_concerns/models/templates/app/models/generic_file.rb +0 -4
- data/lib/generators/curation_concerns/models/templates/config/resque_admin.rb +0 -10
|
@@ -7,7 +7,7 @@ module CurationConcerns
|
|
|
7
7
|
validates(
|
|
8
8
|
:curation_concern_type,
|
|
9
9
|
presence: true,
|
|
10
|
-
inclusion: { in:
|
|
10
|
+
inclusion: { in: ->(record) { record.registered_curation_concern_types } }
|
|
11
11
|
)
|
|
12
12
|
|
|
13
13
|
def all_curation_concern_classes
|
|
@@ -15,7 +15,7 @@ module CurationConcerns
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def registered_curation_concern_types
|
|
18
|
-
CurationConcerns.
|
|
18
|
+
CurationConcerns.config.registered_curation_concern_types
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def possible_curation_concern_types
|
|
@@ -25,17 +25,17 @@ module CurationConcerns
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def curation_concern_class
|
|
28
|
-
if possible_curation_concern_types.detect
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
if possible_curation_concern_types.detect do|_name, class_name|
|
|
29
|
+
class_name == curation_concern_type
|
|
30
|
+
end
|
|
31
31
|
self.class.to_class(curation_concern_type)
|
|
32
32
|
else
|
|
33
|
-
|
|
33
|
+
fail 'Invalid :curation_concern_type'
|
|
34
34
|
end
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
def self.to_class(type)
|
|
38
|
-
# TODO we may want to allow a different (or nil) namespace
|
|
38
|
+
# TODO: we may want to allow a different (or nil) namespace
|
|
39
39
|
type.camelize.constantize
|
|
40
40
|
# begin
|
|
41
41
|
# "::#{type.camelize}".constantize
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
module CurationConcerns
|
|
2
2
|
class QuickClassificationQuery
|
|
3
|
-
|
|
4
3
|
def self.each_for_context(*args, &block)
|
|
5
4
|
new(*args).all.each(&block)
|
|
6
5
|
end
|
|
@@ -10,22 +9,22 @@ module CurationConcerns
|
|
|
10
9
|
def initialize(user, options = {})
|
|
11
10
|
@user = user
|
|
12
11
|
@concern_name_normalizer = options.fetch(:concern_name_normalizer, ClassifyConcern.method(:to_class))
|
|
13
|
-
@registered_curation_concern_names = options.fetch(:registered_curation_concern_names, CurationConcerns.
|
|
12
|
+
@registered_curation_concern_names = options.fetch(:registered_curation_concern_names, CurationConcerns.config.registered_curation_concern_types)
|
|
14
13
|
end
|
|
15
14
|
|
|
16
15
|
def all
|
|
17
16
|
ActiveFedora::Base.logger.debug "User is #{user}"
|
|
18
17
|
ActiveFedora::Base.logger.debug "try is #{normalized_curation_concern_names.first}"
|
|
19
18
|
ActiveFedora::Base.logger.debug "can is #{user.can?(:create, normalized_curation_concern_names.first)}"
|
|
20
|
-
normalized_curation_concern_names.select {|klass| user.can?(:create, klass)}
|
|
19
|
+
normalized_curation_concern_names.select { |klass| user.can?(:create, klass) }
|
|
21
20
|
end
|
|
22
21
|
|
|
23
22
|
private
|
|
24
23
|
|
|
25
|
-
|
|
24
|
+
attr_reader :concern_name_normalizer, :registered_curation_concern_names
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
def normalized_curation_concern_names
|
|
27
|
+
registered_curation_concern_names.collect { |name| concern_name_normalizer.call(name) }
|
|
28
|
+
end
|
|
30
29
|
end
|
|
31
30
|
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,32 @@
|
|
|
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
|
+
private
|
|
11
|
+
|
|
12
|
+
def derivative_path(object, extension, destination_name)
|
|
13
|
+
file_name = destination_name + extension
|
|
14
|
+
File.join(CurationConcerns.config.derivatives_path, pair_path(object.id, file_name))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def pair_path(id, file_name)
|
|
18
|
+
pair = id.split('').each_slice(2).map(&:join).join('/')
|
|
19
|
+
"#{pair}-#{file_name}"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def extension_for(destination_name)
|
|
23
|
+
case destination_name
|
|
24
|
+
when 'thumbnail'
|
|
25
|
+
".#{MIME::Types.type_for('jpg').first.extensions.first}"
|
|
26
|
+
else
|
|
27
|
+
".#{destination_name}"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
data/app/services/curation_concerns/{generic_file_audit_service.rb → file_set_audit_service.rb}
RENAMED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
module CurationConcerns
|
|
2
|
-
class
|
|
3
|
-
attr_reader :
|
|
2
|
+
class FileSetAuditService
|
|
3
|
+
attr_reader :file_set
|
|
4
4
|
def initialize(file)
|
|
5
|
-
@
|
|
5
|
+
@file_set = file
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
NO_RUNS = 999
|
|
@@ -10,20 +10,20 @@ module CurationConcerns
|
|
|
10
10
|
# provides a human readable version of the audit status
|
|
11
11
|
def human_readable_audit_status(stat)
|
|
12
12
|
case stat
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
when 0
|
|
14
|
+
'failing'
|
|
15
|
+
when 1
|
|
16
|
+
'passing'
|
|
17
|
+
else
|
|
18
|
+
stat
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
# Audits each version of each file if it hasn't been audited recently
|
|
23
23
|
# Returns the set of most recent audit status for each version of the content file
|
|
24
24
|
# @param [Hash] log container for messages, mapping file ids to status
|
|
25
|
-
def audit(log={})
|
|
26
|
-
|
|
25
|
+
def audit(log = {})
|
|
26
|
+
file_set.files.each { |f| log[f.id] = audit_file(f) }
|
|
27
27
|
log
|
|
28
28
|
end
|
|
29
29
|
|
|
@@ -32,7 +32,7 @@ module CurationConcerns
|
|
|
32
32
|
# Retrieve or generate the audit check for a file (all versions are checked for versioned files)
|
|
33
33
|
# @param [ActiveFedora::File] file to audit
|
|
34
34
|
# @param [Array] log container for messages
|
|
35
|
-
def audit_file(file, log=[])
|
|
35
|
+
def audit_file(file, log = [])
|
|
36
36
|
versions = file.has_versions? ? file.versions.all : file
|
|
37
37
|
versions.each { |v| log << audit_file_version(file.id, v.uri) }
|
|
38
38
|
log
|
|
@@ -41,9 +41,9 @@ module CurationConcerns
|
|
|
41
41
|
# Retrieve or generate the audit check for a file and provide a human-readable status message.
|
|
42
42
|
# @param [ActiveFedora::File] file to audit
|
|
43
43
|
def audit_stat(file)
|
|
44
|
-
audit_results = audit_file(file).collect { |result| result[
|
|
44
|
+
audit_results = audit_file(file).collect { |result| result['pass'] }
|
|
45
45
|
# check how many non runs we had
|
|
46
|
-
non_runs = audit_results.reduce(0) { |sum, value| value == NO_RUNS ? sum
|
|
46
|
+
non_runs = audit_results.reduce(0) { |sum, value| value == NO_RUNS ? sum + 1 : sum }
|
|
47
47
|
if non_runs == 0
|
|
48
48
|
audit_results.reduce(true) { |sum, value| sum && value }
|
|
49
49
|
elsif non_runs < audit_results.length
|
|
@@ -58,10 +58,10 @@ module CurationConcerns
|
|
|
58
58
|
# @param [String] file_id used to find the file within its parent object (usually "original_file")
|
|
59
59
|
# @param [String] version_uri the version to be audited (or the file uri for non-versioned files)
|
|
60
60
|
def audit_file_version(file_id, version_uri)
|
|
61
|
-
latest_audit = ChecksumAuditLog.logs_for(
|
|
61
|
+
latest_audit = ChecksumAuditLog.logs_for(file_set.id, file_id).first
|
|
62
62
|
return latest_audit unless needs_audit?(latest_audit)
|
|
63
|
-
|
|
64
|
-
latest_audit || ChecksumAuditLog.new(pass: NO_RUNS,
|
|
63
|
+
AuditJob.perform_later(file_set.id, file_id, version_uri.to_s)
|
|
64
|
+
latest_audit || ChecksumAuditLog.new(pass: NO_RUNS, file_set_id: file_set.id, file_id: file_id, version: version_uri)
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
# Check if time since the last audit is greater than the maximum days allowed between audits
|
|
@@ -80,6 +80,5 @@ module CurationConcerns
|
|
|
80
80
|
def days_since_last_audit(latest_audit)
|
|
81
81
|
(DateTime.now - latest_audit.updated_at.to_date).to_i
|
|
82
82
|
end
|
|
83
|
-
|
|
84
83
|
end
|
|
85
84
|
end
|
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
end
|
|
9
|
+
|
|
10
|
+
def thumbnail_path
|
|
11
|
+
self.class.thumbnail_path_service.call(object)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
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,40 @@
|
|
|
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
|
+
client.lock(key, @ttl) do |locked|
|
|
19
|
+
if locked
|
|
20
|
+
yield
|
|
21
|
+
else
|
|
22
|
+
raise UnableToAcquireLockError
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def uri
|
|
30
|
+
@uri ||= begin
|
|
31
|
+
opts = options
|
|
32
|
+
URI("#{opts[:scheme]}://#{opts[:host]}:#{opts[:port]}").to_s
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def options
|
|
37
|
+
::Resque.redis.redis.client.options
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
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
|
|
@@ -2,8 +2,8 @@ module CurationConcerns
|
|
|
2
2
|
class VersioningService
|
|
3
3
|
# Make a version and record the version committer
|
|
4
4
|
# @param [ActiveFedora::File] content
|
|
5
|
-
# @param [User] user
|
|
6
|
-
def self.create(content, user=nil)
|
|
5
|
+
# @param [User, String] user
|
|
6
|
+
def self.create(content, user = nil)
|
|
7
7
|
content.create_version
|
|
8
8
|
record_committer(content, user) if user
|
|
9
9
|
end
|
|
@@ -13,15 +13,14 @@ module CurationConcerns
|
|
|
13
13
|
file.versions.last
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
end
|
|
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
|
|
26
25
|
end
|
|
27
26
|
end
|