Class: Hyrax::WorkUploadsHandler

Inherits:
Object
  • Object
show all
Includes:
Lockable
Defined in:
app/services/hyrax/work_uploads_handler.rb

Overview

TODO:

make this genuinely retry-able. if we fail after creating some of the file_sets, but not attaching them to works, we should resolve that incomplete work on subsequent runs.

Mediates uploads to a work.

Given an existing Work object, `#add` some set of files, then call `#attach` to handle creation/attachment of File Sets, and trigger persistence of files to the storage backend.

This class provides both an interface and a concrete implementation. Applications that want to handle file attachment differently (e.g. by making them completely synchronous, by attaching file sets to a different work attribute, by supporting another file/IO class, etc…) can use a different `Handler` implementation. The only guarantee made by the interface is that the process of persisting the relationship between `work` and the provided `files` will start when `#attach` is called.

This base implementation accepts only `Hyrax::UploadedFile` instances and, for each one, creates a `Hyrax::FileSet` with permissions matching those on `work`, and appends that FileSet to `member_ids`. The `FileSet` will be added in the order that the `UploadedFiles` are passed in. If the work has a `nil` `representative_id` and/or `thumbnail_id`, the first `FileSet` will be set to that value. An `IngestJob` will be equeued, for each `FileSet`. When all of the `files` have been processed, the work will be saved with the added members. While this is happening, we take a lock on the work via `Lockable` (Redis/Redlock).

This also publishes events as required by `Hyrax.publisher`.

Examples:

Hyrax::WorkUploadsHandler.new(work: my_work)
  .add(files: [file1, file2])
  .attach

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Lockable

#acquire_lock_for, #lock_manager

Constructor Details

#initialize(work:, persister: Hyrax.persister) ⇒ WorkUploadsHandler

Returns a new instance of WorkUploadsHandler.

Parameters:

  • work (Hyrax::Work)
  • persister (#save) (defaults to: Hyrax.persister)

    the valkyrie persister to use


56
57
58
59
# File 'app/services/hyrax/work_uploads_handler.rb', line 56

def initialize(work:, persister: Hyrax.persister)
  @work = work
  @persister = persister
end

Instance Attribute Details

#filesEnumberable<Hyrax::UploadedFile> (readonly)

Returns:


51
52
53
# File 'app/services/hyrax/work_uploads_handler.rb', line 51

def files
  @files
end

#workObject (readonly)


51
# File 'app/services/hyrax/work_uploads_handler.rb', line 51

attr_reader :files, :work

Instance Method Details

#add(files:) ⇒ WorkFileSetManager

Note:

we immediately and silently discard uploads with an existing file_set_uri, in a half-considered attempt at supporting idempotency (for job retries). this is for legacy/AttachFilesToWorkJob compatibility, but could stand for a robust reimplementation.

Returns self.

Parameters:

Returns:

  • (WorkFileSetManager)

    self

Raises:

  • (ArgumentError)

    if any of the uploaded files are not an `UploadedFile`


74
75
76
77
78
# File 'app/services/hyrax/work_uploads_handler.rb', line 74

def add(files:)
  validate_files(files) &&
    @files = Array.wrap(files).reject { |f| f.file_set_uri.present? }
  self
end

#attachBoolean

Create filesets for each added file

Returns:

  • (Boolean)

    true if all requested files were attached


86
87
88
89
90
91
92
93
94
95
# File 'app/services/hyrax/work_uploads_handler.rb', line 86

def attach
  return true if Array.wrap(files).empty? # short circuit to avoid aquiring a lock we won't use

  acquire_lock_for(work.id) do
    event_payloads = files.each_with_object([]) { |file, arry| arry << make_file_set_and_ingest(file) }
    @persister.save(resource: work)
    Hyrax.publisher.publish('object.metadata.updated', object: work, user: files.first.user)
    event_payloads.each { |payload| Hyrax.publisher.publish('file.set.attached', payload) }
  end
end