curation_concerns-models 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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