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.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -0
  3. data/Rakefile +1 -1
  4. data/app/actors/concerns/curation_concerns/manages_embargoes_actor.rb +11 -19
  5. data/app/actors/curation_concerns/base_actor.rb +41 -45
  6. data/app/actors/curation_concerns/embargo_actor.rb +19 -0
  7. data/app/actors/curation_concerns/file_set_actor.rb +200 -0
  8. data/app/actors/curation_concerns/lease_actor.rb +19 -0
  9. data/app/actors/curation_concerns/work_actor_behavior.rb +55 -58
  10. data/app/indexers/curation_concerns/collection_indexer.rb +10 -0
  11. data/app/indexers/curation_concerns/file_set_indexing_service.rb +24 -0
  12. data/app/{services/curation_concerns/generic_work_indexing_service.rb → indexers/curation_concerns/work_indexing_service.rb} +6 -6
  13. data/app/jobs/active_fedora_id_based_job.rb +5 -12
  14. data/app/jobs/audit_job.rb +11 -17
  15. data/app/jobs/characterize_job.rb +8 -7
  16. data/app/jobs/create_derivatives_job.rb +8 -11
  17. data/app/jobs/import_url_job.rb +12 -25
  18. data/app/jobs/ingest_file_job.rb +16 -0
  19. data/app/jobs/ingest_local_file_job.rb +14 -35
  20. data/app/jobs/resolrize_job.rb +3 -5
  21. data/app/jobs/upload_set_update_job.rb +68 -0
  22. data/app/models/checksum_audit_log.rb +2 -3
  23. data/app/models/concerns/curation_concerns/ability.rb +18 -10
  24. data/app/models/concerns/curation_concerns/basic_metadata.rb +1 -3
  25. data/app/models/concerns/curation_concerns/collection_behavior.rb +13 -14
  26. data/app/models/concerns/curation_concerns/file_set/belongs_to_upload_sets.rb +15 -0
  27. data/app/models/concerns/curation_concerns/{generic_file → file_set}/belongs_to_works.rb +8 -14
  28. data/app/models/concerns/curation_concerns/file_set/derivatives.rb +54 -0
  29. data/app/models/concerns/curation_concerns/{generic_file → file_set}/full_text_indexing.rb +1 -2
  30. data/app/models/concerns/curation_concerns/{generic_file → file_set}/indexing.rb +2 -2
  31. data/app/models/concerns/curation_concerns/{generic_file → file_set}/versions.rb +2 -3
  32. data/app/models/concerns/curation_concerns/file_set_behavior.rb +36 -0
  33. data/app/models/concerns/curation_concerns/generic_file.rb +1 -1
  34. data/app/models/concerns/curation_concerns/has_representative.rb +6 -7
  35. data/app/models/concerns/curation_concerns/human_readable_type.rb +5 -7
  36. data/app/models/concerns/curation_concerns/permissions.rb +2 -2
  37. data/app/models/concerns/curation_concerns/permissions/readable.rb +0 -1
  38. data/app/models/concerns/curation_concerns/permissions/writable.rb +10 -51
  39. data/app/models/concerns/curation_concerns/serializers.rb +3 -5
  40. data/app/models/concerns/curation_concerns/solr_document_behavior.rb +37 -40
  41. data/app/models/concerns/curation_concerns/upload_set_behavior.rb +38 -0
  42. data/app/models/concerns/curation_concerns/user.rb +4 -51
  43. data/app/models/concerns/curation_concerns/with_file_sets.rb +28 -0
  44. data/app/models/concerns/curation_concerns/{generic_work_behavior.rb → work_behavior.rb} +12 -6
  45. data/app/models/curation_concerns/classify_concern.rb +7 -7
  46. data/app/models/curation_concerns/quick_classification_query.rb +6 -7
  47. data/app/models/single_use_link.rb +34 -0
  48. data/app/models/upload_set.rb +3 -0
  49. data/app/services/curation_concerns/derivative_path.rb +32 -0
  50. data/app/services/curation_concerns/{generic_file_audit_service.rb → file_set_audit_service.rb} +17 -18
  51. data/app/services/curation_concerns/indexes_thumbnails.rb +14 -0
  52. data/app/services/curation_concerns/local_file_service.rb +10 -0
  53. data/app/services/curation_concerns/lock_manager.rb +40 -0
  54. data/app/services/curation_concerns/noid.rb +1 -1
  55. data/app/services/curation_concerns/persist_derivatives.rb +33 -0
  56. data/app/services/curation_concerns/persist_directly_contained_output_file_service.rb +26 -0
  57. data/app/services/curation_concerns/repository_audit_service.rb +1 -3
  58. data/app/services/curation_concerns/thumbnail_path_service.rb +46 -0
  59. data/app/services/curation_concerns/time_service.rb +7 -0
  60. data/app/services/curation_concerns/versioning_service.rb +11 -12
  61. data/curation_concerns-models.gemspec +6 -6
  62. data/lib/curation_concerns/configuration.rb +154 -0
  63. data/lib/curation_concerns/messages.rb +26 -26
  64. data/lib/curation_concerns/models.rb +5 -14
  65. data/lib/curation_concerns/models/engine.rb +0 -30
  66. data/lib/curation_concerns/models/utils.rb +4 -4
  67. data/lib/curation_concerns/models/version.rb +1 -1
  68. data/lib/generators/curation_concerns/models/abstract_migration_generator.rb +8 -7
  69. data/lib/generators/curation_concerns/models/clamav_generator.rb +3 -3
  70. data/lib/generators/curation_concerns/models/install_generator.rb +13 -20
  71. data/lib/generators/curation_concerns/models/templates/app/models/file_set.rb +4 -0
  72. data/lib/generators/curation_concerns/models/templates/config/clamav.rb +1 -1
  73. data/lib/generators/curation_concerns/models/templates/config/curation_concerns.rb +52 -65
  74. data/lib/generators/curation_concerns/models/templates/config/redis_config.rb +13 -17
  75. data/lib/generators/curation_concerns/models/templates/config/resque_config.rb +2 -1
  76. data/lib/generators/curation_concerns/models/templates/migrations/create_checksum_audit_logs.rb +3 -3
  77. data/lib/generators/curation_concerns/models/templates/migrations/create_single_use_links.rb +12 -0
  78. data/lib/tasks/curation_concerns-models_tasks.rake +4 -62
  79. data/lib/tasks/migrate.rake +1 -1
  80. data/lib/tasks/resque.rake +1 -0
  81. data/lib/tasks/solr_reindex.rake +1 -1
  82. metadata +59 -52
  83. data/app/actors/curation_concerns/generic_file_actor.rb +0 -150
  84. data/app/jobs/active_fedora_pid_based_job.rb +0 -6
  85. data/app/jobs/copy_permissions_job.rb +0 -24
  86. data/app/models/concerns/curation_concerns/generic_file/characterization.rb +0 -89
  87. data/app/models/concerns/curation_concerns/generic_file/content.rb +0 -8
  88. data/app/models/concerns/curation_concerns/generic_file/export.rb +0 -343
  89. data/app/models/concerns/curation_concerns/generic_file_behavior.rb +0 -44
  90. data/app/models/concerns/curation_concerns/with_basic_metadata.rb +0 -98
  91. data/app/models/concerns/curation_concerns/with_generic_files.rb +0 -29
  92. data/app/models/datastreams/fits_datastream.rb +0 -148
  93. data/app/services/curation_concerns/characterization_service.rb +0 -71
  94. data/app/services/curation_concerns/full_text_extraction_service.rb +0 -38
  95. data/app/services/curation_concerns/generic_file_indexing_service.rb +0 -14
  96. data/lib/curation_concerns/models/resque.rb +0 -36
  97. data/lib/generators/curation_concerns/models/fulltext_generator.rb +0 -28
  98. data/lib/generators/curation_concerns/models/templates/app/models/generic_file.rb +0 -4
  99. 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: lambda { |record| record.registered_curation_concern_types } }
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.configuration.registered_curation_concern_types
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{|name, class_name|
29
- class_name == curation_concern_type
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
- raise RuntimeError, "Invalid :curation_concern_type"
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.configuration.registered_curation_concern_types)
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
- attr_reader :concern_name_normalizer, :registered_curation_concern_names
24
+ attr_reader :concern_name_normalizer, :registered_curation_concern_names
26
25
 
27
- def normalized_curation_concern_names
28
- registered_curation_concern_names.collect{|name| concern_name_normalizer.call(name) }
29
- end
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,3 @@
1
+ class UploadSet < ActiveFedora::Base
2
+ include CurationConcerns::UploadSetBehavior
3
+ 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
@@ -1,8 +1,8 @@
1
1
  module CurationConcerns
2
- class GenericFileAuditService
3
- attr_reader :generic_file
2
+ class FileSetAuditService
3
+ attr_reader :file_set
4
4
  def initialize(file)
5
- @generic_file = file
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
- when 0
14
- 'failing'
15
- when 1
16
- 'passing'
17
- else
18
- stat
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
- generic_file.files.each { |f| log[f.id] = audit_file(f) }
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["pass"] }
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 += 1 : 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(generic_file.id, file_id).first
61
+ latest_audit = ChecksumAuditLog.logs_for(file_set.id, file_id).first
62
62
  return latest_audit unless needs_audit?(latest_audit)
63
- CurationConcerns.queue.push(AuditJob.new(generic_file.id, file_id, version_uri))
64
- latest_audit || ChecksumAuditLog.new(pass: NO_RUNS, generic_file_id: generic_file.id, file_id: file_id, version: version_uri)
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
@@ -20,4 +20,4 @@ module CurationConcerns
20
20
  @service ||= ActiveFedora::Noid::Service.new
21
21
  end
22
22
  end
23
- 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
@@ -1,9 +1,7 @@
1
1
  module CurationConcerns
2
2
  class RepositoryAuditService
3
3
  def self.audit_everything
4
- ::GenericFile.find_each do |gf|
5
- gf.audit
6
- end
4
+ ::FileSet.find_each(&:audit)
7
5
  end
8
6
  end
9
7
  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,7 @@
1
+ module CurationConcerns
2
+ class TimeService
3
+ def self.time_in_utc
4
+ DateTime.now.utc
5
+ end
6
+ end
7
+ 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
- protected
17
-
18
- # Record the version committer of the last version
19
- # @param [ActiveFedora::File] content
20
- # @param [User] user
21
- def self.record_committer(content, user)
22
- version = latest_version_of(content)
23
- return if version.nil?
24
- VersionCommitter.create(version_id: version.uri, committer_login: user.user_key)
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