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

pulibrary / pdc_describe / 7ae96b6b-0a64-4479-9fa1-8ba6526e2c87

20 Mar 2024 12:42PM UTC coverage: 30.068% (-66.2%) from 96.266%
7ae96b6b-0a64-4479-9fa1-8ba6526e2c87

Pull #1701

circleci

leefaisonr
makes it so that links open in new window
Pull Request #1701: Update language on submission form

1019 of 3389 relevant lines covered (30.07%)

0.4 hits per line

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

20.39
/app/controllers/works_controller.rb
1
# frozen_string_literal: true
2

3
require "nokogiri"
1✔
4
require "open-uri"
1✔
5

6
# rubocop:disable Metrics/ClassLength
7
class WorksController < ApplicationController
1✔
8
  include ERB::Util
1✔
9
  around_action :rescue_aasm_error, only: [:approve, :withdraw, :resubmit, :validate, :create, :new_submission]
1✔
10

11
  skip_before_action :authenticate_user!
1✔
12
  before_action :authenticate_user!, unless: :public_request?
1✔
13

14
  def index
1✔
15
    @works = Work.all
×
16
    respond_to do |format|
×
17
      format.html
×
18
      format.rss { render layout: false }
×
19
    end
20
  end
21

22
  # Renders the "step 0" information page before creating a new dataset
23
  def new
1✔
24
    group = Group.find_by(code: params[:group_code]) || current_user.default_group
×
25
    @work = Work.new(created_by_user_id: current_user.id, group:)
×
26
    @work_decorator = WorkDecorator.new(@work, current_user)
×
27
    @form_resource_decorator = FormResourceDecorator.new(@work, current_user)
×
28
    if wizard_mode?
×
29
      render "new_submission"
×
30
    end
31
  end
32

33
  def create
1✔
34
    @work = Work.new(created_by_user_id: current_user.id, group_id: params_group_id, user_entered_doi: params["doi"].present?)
×
35
    @work.resource = FormToResourceService.convert(params, @work)
×
36
    @work.resource.migrated = migrated?
×
37
    if @work.valid?
×
38
      @work.draft!(current_user)
×
39
      upload_service = WorkUploadsEditService.new(@work, current_user)
×
40
      upload_service.update_precurated_file_list(added_files_param, deleted_files_param)
×
41
      redirect_to work_url(@work), notice: "Work was successfully created."
×
42
    else
43
      @work_decorator = WorkDecorator.new(@work, current_user)
×
44
      @form_resource_decorator = FormResourceDecorator.new(@work, current_user)
×
45
      render :new, status: :unprocessable_entity
×
46
    end
47
  end
48

49
  # Creates the new dataset
50
  def new_submission
1✔
51
    default_group_id = current_user.default_group.id
×
52
    @work = Work.new(created_by_user_id: current_user.id, group_id: default_group_id)
×
53
    @work.resource = FormToResourceService.convert(params, @work)
×
54
    @work.draft!(current_user)
×
55
    redirect_to edit_work_path(@work, wizard: true)
×
56
  end
57

58
  ##
59
  # Show the information for the dataset with the given id
60
  # When requested as .json, return the internal json resource
61
  def show
1✔
62
    @work = Work.find(params[:id])
×
63
    UpdateSnapshotJob.perform_later(work_id: @work.id, last_snapshot_id: work.upload_snapshots.first&.id)
×
64
    @work_decorator = WorkDecorator.new(@work, current_user)
×
65

66
    respond_to do |format|
×
67
      format.html do
×
68
        # Ensure that the Work belongs to a Group
69
        group = @work_decorator.group
×
70
        raise(Work::InvalidGroupError, "The Work #{@work.id} does not belong to any Group") unless group
×
71

72
        @can_curate = current_user.can_admin?(group)
×
73
        @work.mark_new_notifications_as_read(current_user.id)
×
74
      end
75
      format.json { render json: @work.to_json }
×
76
    end
77
  end
78

79
  def file_list
1✔
80
    if params[:id] == "NONE"
×
81
      # This is a special case when we render the file list for a work being created
82
      # (i.e. it does not have an id just yet)
83
      render json: []
×
84
    else
85
      @work = Work.find(params[:id])
×
86
      render json: @work.file_list
×
87
    end
88
  end
89

90
  def resolve_doi
1✔
91
    @work = Work.find_by_doi(params[:doi])
×
92
    redirect_to @work
×
93
  end
94

95
  def resolve_ark
1✔
96
    @work = Work.find_by_ark(params[:ark])
×
97
    redirect_to @work
×
98
  end
99

100
  # GET /works/1/edit
101
  # rubocop:disable Metrics/MethodLength
102
  def edit
1✔
103
    @work = Work.find(params[:id])
×
104
    @work_decorator = WorkDecorator.new(@work, current_user)
×
105
    if current_user && @work.editable_by?(current_user)
×
106
      if @work.approved? && !@work.administered_by?(current_user)
×
107
        Honeybadger.notify("Can not edit work: #{@work.id} is approved but #{current_user.uid} is not admin")
×
108
        redirect_to root_path, notice: I18n.t("works.uneditable.approved")
×
109
      else
110
        @uploads = @work.uploads
×
111
        @wizard_mode = wizard_mode?
×
112
        @form_resource_decorator = FormResourceDecorator.new(@work, current_user)
×
113
        render "edit"
×
114
      end
115
    else
116
      Honeybadger.notify("Can not edit work: #{@work.id} is not editable by #{current_user.uid}")
×
117
      redirect_to root_path, notice: I18n.t("works.uneditable.privs")
×
118
    end
119
  end
120
  # rubocop:enable Metrics/MethodLength
121

122
  def update
1✔
123
    @work = Work.find(params[:id])
×
124
    if current_user.blank? || !@work.editable_by?(current_user)
×
125
      Honeybadger.notify("Can not update work: #{@work.id} is not editable by #{current_user.uid}")
×
126
      redirect_to root_path, notice: I18n.t("works.uneditable.privs")
×
127
    elsif !@work.editable_in_current_state?(current_user)
×
128
      Honeybadger.notify("Can not update work: #{@work.id} is not editable in current state by #{current_user.uid}")
×
129
      redirect_to root_path, notice: I18n.t("works.uneditable.approved")
×
130
    else
131
      update_work
×
132
    end
133
  end
134

135
  # Prompt to select how to submit their files
136
  def attachment_select
1✔
137
    @work = Work.find(params[:id])
×
138
    @wizard_mode = true
×
139
  end
140

141
  # User selected a specific way to submit their files
142
  def attachment_selected
1✔
143
    @work = Work.find(params[:id])
×
144
    @wizard_mode = true
×
145
    @work.files_location = params["attachment_type"]
×
146
    @work.save!
×
147

148
    # create a directory for the work if the curator will need to move files by hand
149
    @work.s3_query_service.create_directory if @work.files_location != "file_upload"
×
150

151
    next_url = case @work.files_location
×
152
               when "file_upload"
153
                 work_file_upload_url(@work)
×
154
               when "file_cluster"
155
                 work_file_cluster_url(@work)
×
156
               else
157
                 work_file_other_url(@work)
×
158
               end
159
    redirect_to next_url
×
160
  end
161

162
  # Allow user to upload files directly
163
  def file_upload
1✔
164
    @work = Work.find(params[:id])
×
165
  end
166

167
  def file_uploaded
1✔
168
    @work = Work.find(params[:id])
×
169
    files = pre_curation_uploads_param || []
×
170
    if files.count > 0
×
171
      upload_service = WorkUploadsEditService.new(@work, current_user)
×
172
      @work = upload_service.update_precurated_file_list(files, [])
×
173
      @work.save!
×
174
      @work.reload_snapshots
×
175
    end
176
    redirect_to(work_review_path)
×
177
  rescue StandardError => active_storage_error
178
    Rails.logger.error("Failed to attach the file uploads for the work #{@work.doi}: #{active_storage_error}")
×
179
    flash[:notice] = "Failed to attach the file uploads for the work #{@work.doi}: #{active_storage_error}. Please contact rdss@princeton.edu for assistance."
×
180

181
    redirect_to work_file_upload_path(@work)
×
182
  end
183

184
  # Allow user to indicate where their files are located in the PUL Research Cluster
185
  def file_cluster
1✔
186
    @work = Work.find(params[:id])
×
187
  end
188

189
  # Allow user to indicate where their files are located in the WWW
190
  def file_other
1✔
191
    @work = Work.find(params[:id])
×
192
  end
193

194
  def review
1✔
195
    @work = Work.find(params[:id])
×
196
    if request.method == "POST"
×
197
      @work.location_notes = params["location_notes"]
×
198
      @work.save!
×
199
    end
200
  end
201

202
  def validate
1✔
203
    @work = Work.find(params[:id])
×
204
    @work.submission_notes = params["submission_notes"]
×
205
    @uploads = @work.uploads
×
206
    @wizard_mode = true
×
207
    @work.complete_submission!(current_user)
×
208
    redirect_to user_url(current_user)
×
209
  end
210

211
  def approve
1✔
212
    @work = Work.find(params[:id])
×
213
    @work.approve!(current_user)
×
214
    flash[:notice] = "Your files are being moved to the post-curation bucket in the background. Depending on the file sizes this may take some time."
×
215
    redirect_to work_path(@work)
×
216
  end
217

218
  def withdraw
1✔
219
    @work = Work.find(params[:id])
×
220
    @work.withdraw!(current_user)
×
221
    redirect_to work_path(@work)
×
222
  end
223

224
  def resubmit
1✔
225
    @work = Work.find(params[:id])
×
226
    @work.resubmit!(current_user)
×
227
    redirect_to work_path(@work)
×
228
  end
229

230
  def assign_curator
1✔
231
    work = Work.find(params[:id])
×
232
    work.change_curator(params[:uid], current_user)
×
233
    if work.errors.count > 0
×
234
      render json: { errors: work.errors.map(&:type) }, status: :bad_request
×
235
    else
236
      render json: {}
×
237
    end
238
  rescue => ex
239
    Rails.logger.error("Error changing curator for work: #{work.id}. Exception: #{ex.message}")
×
240
    render json: { errors: ["Cannot save dataset"] }, status: :bad_request
×
241
  end
242

243
  def add_message
1✔
244
    work = Work.find(params[:id])
×
245
    if params["new-message"].present?
×
246
      new_message_param = params["new-message"]
×
247
      sanitized_new_message = html_escape(new_message_param)
×
248

249
      work.add_message(sanitized_new_message, current_user.id)
×
250
    end
251
    redirect_to work_path(id: params[:id])
×
252
  end
253

254
  def add_provenance_note
1✔
255
    work = Work.find(params[:id])
×
256
    if params["new-provenance-note"].present?
×
257
      new_date = params["new-provenance-date"]
×
258
      new_label = params["change_label"]
×
259
      new_note = html_escape(params["new-provenance-note"])
×
260

261
      work.add_provenance_note(new_date, new_note, current_user.id, new_label)
×
262
    end
263
    redirect_to work_path(id: params[:id])
×
264
  end
265

266
  # Outputs the Datacite XML representation of the work
267
  def datacite
1✔
268
    work = Work.find(params[:id])
×
269
    render xml: work.to_xml
×
270
  end
271

272
  def datacite_validate
1✔
273
    @errors = []
×
274
    @work = Work.find(params[:id])
×
275
    validator = WorkValidator.new(@work)
×
276
    unless validator.valid_datacite?
×
277
      @errors = @work.errors.full_messages
×
278
    end
279
  end
280

281
  def readme_select
1✔
282
    @work = Work.find(params[:id])
×
283
    readme = Readme.new(@work, current_user)
×
284
    @readme = readme.file_name
×
285
    @wizard = true
×
286
  end
287

288
  def readme_uploaded
1✔
289
    @work = Work.find(params[:id])
×
290
    @wizard = true
×
291
    readme = Readme.new(@work, current_user)
×
292
    readme_error = readme.attach(readme_file_param)
×
293
    if readme_error.nil?
×
294
      redirect_to work_attachment_select_url(@work)
×
295
    else
296
      flash[:notice] = readme_error
×
297
      redirect_to work_readme_select_url(@work)
×
298
    end
299
  end
300

301
  def migrating?
1✔
302
    return @work.resource.migrated if @work&.resource && !params.key?(:migrate)
×
303

304
    params[:migrate]
×
305
  end
306
  helper_method :migrating?
1✔
307

308
  def doi_mutable?
1✔
309
    return true unless !@work.nil? && @work.persisted?
×
310

311
    !@work.approved?
×
312
  end
313
  helper_method :doi_mutable?
1✔
314

315
  # Returns the raw BibTex citation information
316
  def bibtex
1✔
317
    work = Work.find(params[:id])
×
318
    creators = work.resource.creators.map { |creator| "#{creator.family_name}, #{creator.given_name}" }
×
319
    citation = DatasetCitation.new(creators, [work.resource.publication_year], work.resource.titles.first.title, work.resource.resource_type, work.resource.publisher, work.resource.doi)
×
320
    bibtex = citation.bibtex
×
321
    send_data bibtex, filename: "#{citation.bibtex_id}.bibtex", type: "text/plain", disposition: "attachment"
×
322
  end
323

324
  private
1✔
325

326
    # Extract the Work ID parameter
327
    # @return [String]
328
    def work_id_param
1✔
329
      params[:id]
×
330
    end
331

332
    # Find the Work requested by ID
333
    # @return [Work]
334
    def work
1✔
335
      Work.find(work_id_param)
×
336
    end
337

338
    # Determine whether or not the request is for the :index action in the RSS
339
    # response format
340
    # This is to enable PDC Discovery to index approved content via the RSS feed
341
    def rss_index_request?
1✔
342
      action_name == "index" && request.format.symbol == :rss
×
343
    end
344

345
    # Determine whether or not the request is for the :show action in the JSON
346
    # response format
347
    # @return [Boolean]
348
    def json_show_request?
1✔
349
      action_name == "show" && request.format.symbol == :json
×
350
    end
351

352
    # Determine whether or not the requested Work has been approved
353
    # @return [Boolean]
354
    def work_approved?
1✔
355
      work&.state == "approved"
×
356
    end
357

358
    ##
359
    # Public requests are requests that do not require authentication.
360
    # This is to enable PDC Discovery to index approved content via the RSS feed
361
    # and .json calls to individual works without needing to log in as a user.
362
    # Note that only approved works can be fetched for indexing.
363
    def public_request?
1✔
364
      return true if rss_index_request?
×
365
      return true if json_show_request? && work_approved?
×
366
      false
×
367
    end
368

369
    def work_params
1✔
370
      params[:work] || {}
×
371
    end
372

373
    def patch_params
1✔
374
      return {} unless params.key?(:patch)
×
375

376
      params[:patch]
×
377
    end
378

379
    def pre_curation_uploads_param
1✔
380
      return if patch_params.nil?
×
381

382
      patch_params[:pre_curation_uploads]
×
383
    end
384

385
    def readme_file_param
1✔
386
      return if patch_params.nil?
×
387

388
      patch_params[:readme_file]
×
389
    end
390

391
    # rubocop:disable Metrics/AbcSize
392
    # rubocop:disable Metrics/BlockNesting
393
    # rubocop:disable Metrics/CyclomaticComplexity
394
    # rubocop:disable Metrics/MethodLength
395
    # rubocop:disable Metrics/PerceivedComplexity
396
    def rescue_aasm_error
1✔
397
      yield
×
398
    rescue AASM::InvalidTransition => error
399
      message = error.message
×
400
      if @work.errors.count > 0
×
401
        message = @work.errors.to_a.join(", ")
×
402
      end
403
      message.chop! if message.last == "."
×
404
      Honeybadger.notify("Invalid #{@work.current_transition}: #{error.message} errors: #{message}")
×
405
      transition_error_message = "We apologize, the following errors were encountered: #{message}. Please contact the PDC Describe administrators for any assistance."
×
406
      @errors = [transition_error_message]
×
407

408
      if @work.persisted?
×
409
        redirect_to edit_work_url(id: @work.id), notice: transition_error_message, params:
×
410
      else
411
        new_params = {}
×
412
        new_params[:wizard] = wizard_mode? if wizard_mode?
×
413
        new_params[:migrate] = migrating? if migrating?
×
414
        @form_resource_decorator = FormResourceDecorator.new(@work, current_user)
×
415
        redirect_to new_work_url(params: new_params), notice: transition_error_message, params: new_params
×
416
      end
417
    rescue StandardError => generic_error
418
      if action_name == "create"
×
419
        if @work.persisted?
×
420
          Honeybadger.notify("Failed to create the new Dataset #{@work.id}: #{generic_error.message}")
×
421
          @form_resource_decorator = FormResourceDecorator.new(@work, current_user)
×
422
          redirect_to edit_work_url(id: @work.id), notice: "Failed to create the new Dataset #{@work.id}: #{generic_error.message}", params:
×
423
        else
424
          Honeybadger.notify("Failed to create a new Dataset #{@work.id}: #{generic_error.message}")
×
425
          new_params = {}
×
426
          new_params[:wizard] = wizard_mode? if wizard_mode?
×
427
          new_params[:migrate] = migrating? if migrating?
×
428
          @form_resource_decorator = FormResourceDecorator.new(@work, current_user)
×
429
          redirect_to new_work_url(params: new_params), notice: "Failed to create a new Dataset: #{generic_error.message}", params: new_params
×
430
        end
431
      else
432
        redirect_to root_url, notice: "We apologize, an error was encountered: #{generic_error.message}. Please contact the PDC Describe administrators."
×
433
      end
434
    end
435
    # rubocop:enable Metrics/PerceivedComplexity
436
    # rubocop:enable Metrics/MethodLength
437
    # rubocop:enable Metrics/CyclomaticComplexity
438
    # rubocop:enable Metrics/BlockNesting
439
    # rubocop:enable Metrics/AbcSize
440

441
    def error_action
1✔
442
      @form_resource_decorator = FormResourceDecorator.new(@work, current_user)
×
443
      if action_name == "create"
×
444
        :new
×
445
      elsif action_name == "validate"
×
446
        :edit
×
447
      elsif action_name == "new_submission"
×
448
        :new_submission
×
449
      else
450
        @work_decorator = WorkDecorator.new(@work, current_user)
×
451
        :show
×
452
      end
453
    end
454

455
    def wizard_mode?
1✔
456
      params[:wizard] == "true"
×
457
    end
458

459
    def update_work
1✔
460
      @wizard_mode = wizard_mode?
×
461
      upload_service = WorkUploadsEditService.new(@work, current_user)
×
462
      if @work.approved?
×
463
        upload_keys = deleted_files_param || []
×
464
        deleted_uploads = upload_service.find_post_curation_uploads(upload_keys:)
×
465

466
        return head(:forbidden) unless deleted_uploads.empty?
×
467
      else
468
        @work = upload_service.update_precurated_file_list(added_files_param, deleted_files_param)
×
469
      end
470

471
      process_updates
×
472
    end
473

474
    def embargo_date_param
1✔
475
      params["embargo-date"]
×
476
    end
477

478
    def embargo_date
1✔
479
      return nil if embargo_date_param.blank?
×
480

481
      Date.parse(embargo_date_param)
×
482
    rescue Date::Error
483
      Rails.logger.error("Failed to parse the embargo date #{embargo_date_param} for Work #{@work.id}")
×
484
      nil
×
485
    end
486

487
    def update_params
1✔
488
      {
489
        group_id: params_group_id,
×
490
        embargo_date:,
491
        resource: FormToResourceService.convert(params, @work)
492
      }
493
    end
494

495
    def added_files_param
1✔
496
      Array(work_params[:pre_curation_uploads_added])
×
497
    end
498

499
    def deleted_files_param
1✔
500
      deleted_count = (work_params["deleted_files_count"] || "0").to_i
×
501
      (1..deleted_count).map { |i| work_params["deleted_file_#{i}"] }.select(&:present?)
×
502
    end
503

504
    def process_updates
1✔
505
      work_before = @work.dup
×
506
      if @work.update(update_params)
×
507
        work_compare = WorkCompareService.new(work_before, @work)
×
508
        @work.log_changes(work_compare, current_user.id)
×
509

510
        if @wizard_mode
×
511
          redirect_to work_readme_select_url(@work)
×
512
        else
513
          redirect_to work_url(@work), notice: "Work was successfully updated."
×
514
        end
515
      else
516
        # This is needed for rendering HTML views with validation errors
517
        @uploads = @work.uploads
×
518
        @wizard_mode = wizard_mode?
×
519
        @form_resource_decorator = FormResourceDecorator.new(@work, current_user)
×
520

521
        render :edit, status: :unprocessable_entity
×
522
      end
523
    end
524

525
    def params_group_id
1✔
526
      # Do not allow a nil for the group id
527
      @params_group_id ||= begin
×
528
        group_id = params[:group_id]
×
529
        if group_id.blank?
×
530
          group_id = current_user.default_group.id
×
531
          Honeybadger.notify("We got a nil group as part of the parameters #{params} #{request}")
×
532
        end
533
        group_id
×
534
      end
535
    end
536

537
    def migrated?
1✔
538
      return false unless params.key?(:submit)
×
539

540
      params[:submit] == "Migrate"
×
541
    end
542
end
543
# 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