• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pulibrary / pdc_describe / 5db21940-59bd-4742-a25d-02e5e58d6646

pending completion
5db21940-59bd-4742-a25d-02e5e58d6646

Pull #1014

circleci

Carolyn Cole
Creating a folder in Amazon so the curators do not need to do it by hand fixes #1001
Pull Request #1014: Creating a folder in Amazon so the curators do not need to do it by hand

3 of 3 new or added lines in 2 files covered. (100.0%)

1703 of 1872 relevant lines covered (90.97%)

80.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.32
/app/models/work.rb
1
# frozen_string_literal: true
2

3
# rubocop:disable Metrics/ClassLength
4
class Work < ApplicationRecord
1✔
5
  # Errors for cases where there is no valid Collection
6
  class InvalidCollectionError < ::ArgumentError; end
1✔
7

8
  has_many :work_activity, -> { order(updated_at: :desc) }, dependent: :destroy
74✔
9
  has_many :user_work, -> { order(updated_at: :desc) }, dependent: :destroy
6✔
10
  has_many_attached :pre_curation_uploads, service: :amazon_pre_curation
1✔
11

12
  belongs_to :collection
1✔
13
  belongs_to :curator, class_name: "User", foreign_key: "curator_user_id", optional: true
1✔
14

15
  attribute :work_type, :string, default: "DATASET"
1✔
16
  attribute :profile, :string, default: "DATACITE"
1✔
17

18
  attr_accessor :user_entered_doi
1✔
19

20
  alias state_history user_work
1✔
21

22
  include AASM
1✔
23

24
  aasm column: :state do
1✔
25
    state :none, inital: true
1✔
26
    state :draft, :awaiting_approval, :approved, :withdrawn, :tombstone
1✔
27

28
    event :draft, after: :draft_doi do
1✔
29
      transitions from: :none, to: :draft, guard: :valid_to_draft
1✔
30
    end
31

32
    event :complete_submission do
1✔
33
      transitions from: :draft, to: :awaiting_approval, guard: :valid_to_submit
1✔
34
    end
35

36
    event :request_changes do
1✔
37
      transitions from: :awaiting_approval, to: :awaiting_approval, guard: :valid_to_submit
1✔
38
    end
39

40
    event :approve do
1✔
41
      transitions from: :awaiting_approval, to: :approved, guard: :valid_to_approve, after: :publish
1✔
42
    end
43

44
    event :withdraw do
1✔
45
      transitions from: [:draft, :awaiting_approval, :approved], to: :withdrawn
1✔
46
    end
47

48
    event :resubmit do
1✔
49
      transitions from: :withdrawn, to: :draft
1✔
50
    end
51

52
    event :remove do
1✔
53
      transitions from: :withdrawn, to: :tombstone
1✔
54
    end
55

56
    after_all_events :track_state_change
1✔
57
  end
58

59
  def state=(new_state)
1✔
60
    new_state_sym = new_state.to_sym
243✔
61
    valid_states = self.class.aasm.states.map(&:name)
243✔
62
    raise(StandardError, "Invalid state '#{new_state}'") unless valid_states.include?(new_state_sym)
243✔
63
    aasm_write_state_without_persistence(new_state_sym)
242✔
64
  end
65

66
  ##
67
  # Is this work editable by a given user?
68
  # A work is editable when:
69
  # * it is being edited by the person who made it
70
  # * it is being edited by a collection admin of the collection where is resides
71
  # * it is being edited by a super admin
72
  # @param [User]
73
  # @return [Boolean]
74
  def editable_by?(user)
1✔
75
    submitted_by?(user) || administered_by?(user)
20✔
76
  end
77

78
  def editable_in_current_state?(user)
1✔
79
    # anyone with edit privleges can edit a work while it is in draft or awaiting approval
80
    return editable_by?(user) if draft? || awaiting_approval?
8✔
81

82
    # Only admisitrators can edit a work in other states
83
    administered_by?(user)
3✔
84
  end
85

86
  def submitted_by?(user)
1✔
87
    created_by_user_id == user.id
20✔
88
  end
89

90
  def administered_by?(user)
1✔
91
    user.has_role?(:collection_admin, collection)
12✔
92
  end
93

94
  class << self
1✔
95
    def find_by_doi(doi)
1✔
96
      prefix = "10.34770/"
3✔
97
      doi = "#{prefix}#{doi}" unless doi.start_with?(prefix)
3✔
98
      Work.find_by!("metadata @> ?", JSON.dump(doi: doi))
3✔
99
    end
100

101
    def find_by_ark(ark)
1✔
102
      prefix = "ark:/"
3✔
103
      ark = "#{prefix}#{ark}" unless ark.start_with?(prefix)
3✔
104
      Work.find_by!("metadata @> ?", JSON.dump(ark: ark))
3✔
105
    end
106

107
    delegate :resource_type_general_values, to: PDCMetadata::Resource
1✔
108

109
    # Determines whether or not a test DOI should be referenced
110
    # (this avoids requests to the DOI API endpoint for non-production deployments)
111
    # @return [Boolean]
112
    def publish_test_doi?
1✔
113
      (Rails.env.development? || Rails.env.test?) && Rails.configuration.datacite.user.blank?
12✔
114
    end
115
  end
116

117
  include Rails.application.routes.url_helpers
1✔
118

119
  before_save do |work|
1✔
120
    # Ensure that the metadata JSONB postgres field is persisted properly
121
    work.metadata = JSON.parse(work.resource.to_json)
417✔
122
    work.save_pre_curation_uploads
417✔
123
  end
124

125
  after_save do |work|
1✔
126
    if work.approved?
416✔
127
      work.reload
33✔
128
    end
129
  end
130

131
  validate do |work|
1✔
132
    if none?
425✔
133
      work.validate_doi
90✔
134
    elsif draft?
335✔
135
      work.valid_to_draft
235✔
136
    else
137
      work.valid_to_submit
100✔
138
    end
139
  end
140

141
  # Overload ActiveRecord.reload method
142
  # https://apidock.com/rails/ActiveRecord/Base/reload
143
  #
144
  # NOTE: Usually `after_save` is a better place to put this kind of code:
145
  #
146
  #   after_save do |work|
147
  #     work.resource = nil
148
  #   end
149
  #
150
  # but that does not work in this case because the block points to a different
151
  # memory object for `work` than the we want we want to reload.
152
  def reload(options = nil)
1✔
153
    super
64✔
154
    # Force `resource` to be reloaded
155
    @resource = nil
64✔
156
    self
64✔
157
  end
158

159
  def validate_doi
1✔
160
    return true unless user_entered_doi
90✔
161
    if /^10.\d{4,9}\/[-._;()\/:a-z0-9\-]+$/.match?(doi.downcase)
×
162
      response = Faraday.get("#{Rails.configuration.datacite.doi_url}#{doi}")
×
163
      errors.add(:base, "Invalid DOI: can not verify it's authenticity") unless response.success? || response.status == 302
×
164
    else
165
      errors.add(:base, "Invalid DOI: does not match format")
×
166
    end
167
    errors.count == 0
×
168
  end
169

170
  def valid_to_draft
1✔
171
    errors.add(:base, "Must provide a title") if resource.main_title.blank?
362✔
172
    validate_ark
362✔
173
    validate_creators
362✔
174
    errors.count == 0
362✔
175
  end
176

177
  def valid_to_submit
1✔
178
    valid_to_draft
113✔
179
    validate_metadata
113✔
180
    errors.count == 0
113✔
181
  end
182

183
  def valid_to_approve(user)
1✔
184
    valid_to_submit
2✔
185
    unless user.has_role? :collection_admin, collection
2✔
186
      errors.add :base, "Unauthorized to Approve"
1✔
187
    end
188
    errors.count == 0
2✔
189
  end
190

191
  def title
1✔
192
    resource.main_title
76✔
193
  end
194

195
  def uploads_attributes
1✔
196
    return [] if approved? # once approved we no longer allow the updating of uploads via the application
1✔
197
    uploads.map do |upload|
1✔
198
      {
199
        id: upload.id,
2✔
200
        key: upload.key,
201
        filename: upload.filename.to_s,
202
        created_at: upload.created_at,
203
        url: upload.url
204
      }
205
    end
206
  end
207

208
  def form_attributes
1✔
209
    {
210
      uploads: uploads_attributes
1✔
211
    }
212
  end
213

214
  def draft_doi
1✔
215
    return if resource.doi.present?
15✔
216
    resource.doi = if self.class.publish_test_doi?
12✔
217
                     Rails.logger.info "Using hard-coded test DOI during development."
1✔
218
                     "10.34770/tbd"
1✔
219
                   else
220
                     result = data_cite_connection.autogenerate_doi(prefix: Rails.configuration.datacite.prefix)
11✔
221
                     if result.success?
11✔
222
                       result.success.doi
10✔
223
                     else
224
                       raise("Error generating DOI. #{result.failure.status} / #{result.failure.reason_phrase}")
1✔
225
                     end
226
                   end
227
    save!
11✔
228
  end
229

230
  def created_by_user
1✔
231
    User.find(created_by_user_id)
139✔
232
  rescue ActiveRecord::RecordNotFound
233
    nil
1✔
234
  end
235

236
  def resource=(resource)
1✔
237
    @resource = resource
337✔
238
    # Ensure that the metadata JSONB postgres field is persisted properly
239
    self.metadata = JSON.parse(resource.to_json)
337✔
240
  end
241

242
  def resource
1✔
243
    @resource ||= PDCMetadata::Resource.new_from_jsonb(metadata)
3,393✔
244
  end
245

246
  def url
1✔
247
    return unless persisted?
×
248

249
    @url ||= url_for(self)
×
250
  end
251

252
  def files_location_upload?
1✔
253
    files_location.blank? || files_location == "file_upload"
×
254
  end
255

256
  def files_location_cluster?
1✔
257
    files_location == "file_cluster"
×
258
  end
259

260
  def files_location_other?
1✔
261
    files_location == "file_other"
×
262
  end
263

264
  def change_curator(curator_user_id, current_user)
1✔
265
    if curator_user_id == "no-one"
5✔
266
      clear_curator(current_user)
1✔
267
    else
268
      update_curator(curator_user_id, current_user)
4✔
269
    end
270
  end
271

272
  def clear_curator(current_user)
1✔
273
    # Update the curator on the Work
274
    self.curator_user_id = nil
2✔
275
    save!
2✔
276

277
    # ...and log the activity
278
    WorkActivity.add_work_activity(id, "Unassigned existing curator", current_user.id, activity_type: WorkActivity::SYSTEM)
2✔
279
  end
280

281
  def update_curator(curator_user_id, current_user)
1✔
282
    # Update the curator on the Work
283
    self.curator_user_id = curator_user_id
5✔
284
    save!
5✔
285

286
    # ...and log the activity
287
    new_curator = User.find(curator_user_id)
4✔
288
    message = if curator_user_id == current_user.id
4✔
289
                "Self-assigned as curator"
1✔
290
              else
291
                "Set curator to @#{new_curator.uid}"
3✔
292
              end
293
    WorkActivity.add_work_activity(id, message, current_user.id, activity_type: WorkActivity::SYSTEM)
4✔
294
  end
295

296
  def curator_or_current_uid(user)
1✔
297
    persisted = if curator.nil?
1✔
298
                  user
1✔
299
                else
300
                  curator
×
301
                end
302
    persisted.uid
1✔
303
  end
304

305
  def add_message(message, current_user_id)
1✔
306
    WorkActivity.add_work_activity(id, message, current_user_id, activity_type: WorkActivity::MESSAGE)
7✔
307
  end
308

309
  def add_provenance_note(date, note, current_user_id)
1✔
310
    WorkActivity.add_work_activity(id, note, current_user_id, activity_type: WorkActivity::PROVENANCE_NOTES, created_at: date)
×
311
  end
312

313
  def log_changes(resource_compare, current_user_id)
1✔
314
    return if resource_compare.identical?
5✔
315
    WorkActivity.add_work_activity(id, resource_compare.differences.to_json, current_user_id, activity_type: WorkActivity::CHANGES)
5✔
316
  end
317

318
  def log_file_changes(changes, current_user_id)
1✔
319
    return if changes.count == 0
×
320
    WorkActivity.add_work_activity(id, changes.to_json, current_user_id, activity_type: WorkActivity::FILE_CHANGES)
×
321
  end
322

323
  def activities
1✔
324
    WorkActivity.activities_for_work(id, WorkActivity::MESSAGE_ACTIVITY_TYPES + WorkActivity::CHANGE_LOG_ACTIVITY_TYPES)
5✔
325
  end
326

327
  def new_notification_count_for_user(user_id)
1✔
328
    WorkActivityNotification.joins(:work_activity)
14✔
329
                            .where(user_id: user_id, read_at: nil)
330
                            .where(work_activity: { work_id: id })
331
                            .count
332
  end
333

334
  # Marks as read the notifications for the given user_id in this work.
335
  # In practice, the user_id is the id of the current user and therefore this method marks the current's user
336
  # notifications as read.
337
  def mark_new_notifications_as_read(user_id)
1✔
338
    activities.each do |activity|
5✔
339
      unread_notifications = WorkActivityNotification.where(user_id: user_id, work_activity_id: activity.id, read_at: nil)
3✔
340
      unread_notifications.each do |notification|
3✔
341
        notification.read_at = Time.now.utc
1✔
342
        notification.save
1✔
343
      end
344
    end
345
  end
346

347
  def current_transition
1✔
348
    aasm.current_event.to_s.humanize.delete("!")
4✔
349
  end
350

351
  def uploads
1✔
352
    return post_curation_uploads if approved?
6✔
353

354
    pre_curation_uploads_fast
6✔
355
  end
356

357
  # Fetches the data from S3 directly bypassing ActiveStorage
358
  def pre_curation_uploads_fast
1✔
359
    s3_query_service.client_s3_files.sort_by(&:filename)
13✔
360
  end
361

362
  # This ensures that new ActiveStorage::Attachment objects can be modified before they are persisted
363
  def save_pre_curation_uploads
1✔
364
    return if pre_curation_uploads.empty?
417✔
365

366
    new_attachments = pre_curation_uploads.reject(&:persisted?)
4✔
367
    return if new_attachments.empty?
4✔
368

369
    save_new_attachments(new_attachments: new_attachments)
2✔
370
  end
371

372
  # Accesses post-curation S3 Bucket Objects
373
  def post_curation_s3_resources
1✔
374
    return [] unless approved?
9✔
375

376
    s3_resources
6✔
377
  end
378
  alias post_curation_uploads post_curation_s3_resources
1✔
379

380
  def s3_client
1✔
381
    s3_query_service.client
×
382
  end
383

384
  delegate :bucket_name, to: :s3_query_service
1✔
385

386
  # Generates the S3 Object key
387
  # @return [String]
388
  def s3_object_key
1✔
389
    "#{doi}/#{id}"
7✔
390
  end
391

392
  # Transmit a HEAD request for the S3 Bucket directory for this Work
393
  # @param bucket_name location to be checked to be found
394
  # @return [Aws::S3::Types::HeadObjectOutput]
395
  def find_post_curation_s3_dir(bucket_name:)
1✔
396
    # TODO: Directories really do not exists in S3
397
    #      if we really need this check then we need to do something else to check the bucket
398
    s3_client.head_object({
×
399
                            bucket: bucket_name,
400
                            key: s3_object_key
401
                          })
402
    true
×
403
  rescue Aws::S3::Errors::NotFound
404
    nil
×
405
  end
406

407
  def as_json(options = nil)
1✔
408
    if options&.present?
3✔
409
      raise(StandardError, "Received options #{options}, but not supported")
×
410
      # Included in signature for compatibility with Rails.
411
    end
412

413
    # Pre-curation files are not accessible externally,
414
    # so we are not interested in listing them in JSON.
415
    # (The items in pre_curation_uploads also have different properties.)
416
    files = post_curation_uploads.map do |upload|
3✔
417
      {
418
        "filename": upload.filename,
×
419
        "size": upload.size,
420
        "url": upload.globus_url
421
      }
422
    end
423

424
    # to_json returns a string of serialized JSON.
425
    # as_json returns the corresponding hash.
426
    {
427
      "resource" => resource.as_json,
3✔
428
      "files" => files,
429
      "collection" => collection.as_json.except("id")
430
    }
431
  end
432

433
  def pre_curation_uploads_count
1✔
434
    s3_query_service.file_count
6✔
435
  end
436

437
  delegate :ark, :doi, :resource_type, :resource_type=, :resource_type_general, :resource_type_general=,
1✔
438
           :to_xml, to: :resource
439

440
  # S3QueryService object associated with this Work
441
  # @return [S3QueryService]
442
  def s3_query_service
1✔
443
    @s3_query_service ||= S3QueryService.new(self, !approved?)
31✔
444
  end
445

446
  protected
1✔
447

448
    # This must be protected, NOT private for ActiveRecord to work properly with this attribute.
449
    #   Protected will still keep others from setting the metatdata, but allows ActiveRecord the access it needs
450
    def metadata=(metadata)
1✔
451
      super
754✔
452
      @resource = PDCMetadata::Resource.new_from_jsonb(metadata)
754✔
453
    end
454

455
  private
1✔
456

457
    def publish(user)
1✔
458
      publish_doi(user)
×
459
      update_ark_information
×
460
      publish_precurated_files
×
461
      save!
×
462
    end
463

464
    # Update EZID (our provider of ARKs) with the new information for this work.
465
    def update_ark_information
1✔
466
      # We only want to update the ark url under certain conditions.
467
      # Set this value in config/update_ark_url.yml
468
      if Rails.configuration.update_ark_url
×
469
        if ark.present?
×
470
          Ark.update(ark, url)
×
471
        end
472
      end
473
    end
474

475
    # Generates the key for ActiveStorage::Attachment and Attachment::Blob objects
476
    # @param attachment [ActiveStorage::Attachment]
477
    # @return [String]
478
    def generate_attachment_key(attachment)
1✔
479
      attachment_filename = attachment.filename.to_s
2✔
480
      attachment_key = attachment.key
2✔
481

482
      # Files actually coming from S3 include the DOI and bucket as part of the file name
483
      #  Files being attached in another manner may not have it, so we should include it.
484
      #  This is really for testing only.
485
      key_base = "#{doi}/#{id}"
2✔
486
      attachment_key = [key_base, attachment_filename].join("/") unless attachment_key.include?(key_base)
2✔
487

488
      attachment_ext = File.extname(attachment_filename)
2✔
489
      attachment_query = attachment_key.gsub(attachment_ext, "")
2✔
490
      results = ActiveStorage::Blob.where("key LIKE :query", query: "%#{attachment_query}%")
2✔
491
      blobs = results.to_a
2✔
492

493
      if blobs.present?
2✔
494
        index = blobs.length + 1
×
495
        attachment_key = attachment_key.gsub(/\.([a-zA-Z0-9\.]+)$/, "_#{index}.\\1")
×
496
      end
497

498
      attachment_key
2✔
499
    end
500

501
    def track_state_change(user, state = aasm.to_state)
1✔
502
      uw = UserWork.new(user_id: user.id, work_id: id, state: state)
57✔
503
      uw.save!
57✔
504
      WorkActivity.add_work_activity(id, "marked as #{state.to_s.titleize}", user.id, activity_type: WorkActivity::SYSTEM)
57✔
505
      WorkStateTransitionNotification.new(self, user.id).send
57✔
506
    end
507

508
    def data_cite_connection
1✔
509
      @data_cite_connection ||= Datacite::Client.new(username: Rails.configuration.datacite.user,
11✔
510
                                                     password: Rails.configuration.datacite.password,
511
                                                     host: Rails.configuration.datacite.host)
512
    end
513

514
    def validate_ark
1✔
515
      return if ark.blank?
362✔
516
      first_save = id.blank?
15✔
517
      changed_value = metadata["ark"] != ark
15✔
518
      if first_save || changed_value
15✔
519
        errors.add(:base, "Invalid ARK provided for the Work: #{ark}") unless Ark.valid?(ark)
11✔
520
      end
521
    end
522

523
    # rubocop:disable Metrics/AbcSize
524
    def validate_metadata
1✔
525
      return if metadata.blank?
113✔
526
      errors.add(:base, "Must provide a title") if resource.main_title.blank?
113✔
527
      errors.add(:base, "Must provide a description") if resource.description.blank?
113✔
528
      errors.add(:base, "Must indicate the Publisher") if resource.publisher.blank?
113✔
529
      errors.add(:base, "Must indicate the Publication Year") if resource.publication_year.blank?
113✔
530
      errors.add(:base, "Must indicate a Rights statement") if resource.rights.nil?
113✔
531
      errors.add(:base, "Must provide a Version number") if resource.version_number.blank?
113✔
532
      validate_creators
113✔
533
      validate_related_objects
113✔
534
    end
535
    # rubocop:enable Metrics/AbcSize
536

537
    def validate_creators
1✔
538
      if resource.creators.count == 0
475✔
539
        errors.add(:base, "Must provide at least one Creator")
1✔
540
      else
541
        resource.creators.each do |creator|
474✔
542
          if creator.orcid.present? && Orcid.invalid?(creator.orcid)
518✔
543
            errors.add(:base, "ORCID for creator #{creator.value} is not in format 0000-0000-0000-0000")
1✔
544
          end
545
        end
546
      end
547
    end
548

549
    def validate_related_objects
1✔
550
      return if resource.related_objects.empty?
113✔
551
      invalid = resource.related_objects.reject(&:valid?)
1✔
552
      errors.add(:base, "Related Objects are invalid: #{invalid.map(&:errors).join(', ')}") if invalid.count.positive?
1✔
553
    end
554

555
    def publish_doi(user)
1✔
556
      return Rails.logger.info("Publishing hard-coded test DOI during development.") if self.class.publish_test_doi?
×
557

558
      if doi.starts_with?(Rails.configuration.datacite.prefix)
×
559
        result = data_cite_connection.update(id: doi, attributes: doi_attributes)
×
560
        if result.failure?
×
561
          resolved_user = curator_or_current_uid(user)
×
562
          message = "@#{resolved_user} Error publishing DOI. #{result.failure.status} / #{result.failure.reason_phrase}"
×
563
          WorkActivity.add_work_activity(id, message, user.id, activity_type: WorkActivity::DATACITE_ERROR)
×
564
        end
565
      elsif ark.blank? # we can not update the url anywhere
×
566
        Honeybadger.notify("Publishing for a DOI we do not own and no ARK is present: #{doi}")
×
567
      end
568
    end
569

570
    def doi_attribute_url
1✔
571
      "https://datacommons.princeton.edu/discovery/doi/#{doi}"
×
572
    end
573

574
    def doi_attribute_resource
1✔
575
      PDCMetadata::Resource.new_from_jsonb(metadata)
×
576
    end
577

578
    def doi_attribute_xml
1✔
579
      unencoded = doi_attribute_resource.to_xml
×
580
      Base64.encode64(unencoded)
×
581
    end
582

583
    def doi_attributes
1✔
584
      {
585
        "event" => "publish",
×
586
        "xml" => doi_attribute_xml,
587
        "url" => doi_attribute_url
588
      }
589
    end
590

591
    # This needs to be called #before_save
592
    # This ensures that new ActiveStorage::Attachment objects are persisted with custom keys (which are generated from the file name and DOI)
593
    # @param new_attachments [Array<ActiveStorage::Attachment>]
594
    def save_new_attachments(new_attachments:)
1✔
595
      new_attachments.each do |attachment|
2✔
596
        # There are cases (race conditions?) where the ActiveStorage::Blob objects are not persisted
597
        next if attachment.frozen?
2✔
598

599
        # This ensures that the custom key for the ActiveStorage::Attachment and ActiveStorage::Blob objects are generated
600
        generated_key = generate_attachment_key(attachment)
2✔
601
        attachment.blob.key = generated_key
2✔
602
        attachment.blob.save
2✔
603

604
        attachment.save
2✔
605
      end
606
    end
607

608
    # Request S3 Bucket Objects associated with this Work
609
    # @return [Array<S3File>]
610
    def s3_resources
1✔
611
      data_profile = s3_query_service.data_profile
6✔
612
      data_profile.fetch(:objects, [])
6✔
613
    end
614
    alias pre_curation_s3_resources s3_resources
1✔
615

616
    def s3_object_persisted?(s3_file)
1✔
617
      uploads_keys = uploads.map(&:key)
×
618
      uploads_keys.include?(s3_file.key)
×
619
    end
620

621
    def add_pre_curation_s3_object(s3_file)
1✔
622
      return if s3_object_persisted?(s3_file)
×
623

624
      persisted = s3_file.to_blob
×
625
      pre_curation_uploads.attach(persisted)
×
626
    end
627

628
    def publish_precurated_files
1✔
629
      # An error is raised if there are no files to be moved
630
      raise(StandardError, "Attempting to publish a Work without attached uploads for #{s3_object_key}") if pre_curation_uploads_fast.empty? && post_curation_uploads.empty?
×
631

632
      # We need to explicitly access to post-curation services here.
633
      # Lets explicitly create it so the state of the work does not have any impact.
634
      s3_post_curation_query_service = S3QueryService.new(self, false)
×
635

636
      s3_dir = find_post_curation_s3_dir(bucket_name: s3_post_curation_query_service.bucket_name)
×
637
      raise(StandardError, "Attempting to publish a Work with an existing S3 Bucket directory for: #{s3_object_key}") unless s3_dir.nil?
×
638

639
      # Copy the pre-curation S3 Objects to the post-curation S3 Bucket...
640
      transferred_file_errors = s3_query_service.publish_files
×
641

642
      # ...check that the files are indeed now in the post-curation bucket...
643
      if transferred_file_errors.count > 0
×
644
        raise(StandardError, "Failed to validate the uploaded S3 Object #{transferred_file_errors.map(&:key).join(', ')}")
×
645
      end
646
    end
647
end
648
# rubocop:enable Metrics/ClassLength
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc