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

pulibrary / pdc_describe / a13315e3-e13e-4c5f-a778-a1981980f07d

15 May 2024 01:56PM UTC coverage: 95.871% (-0.04%) from 95.909%
a13315e3-e13e-4c5f-a778-a1981980f07d

Pull #1813

circleci

jrgriffiniii
Ensures that one and only one README file is uploaded and that there is one or more files uploaded for any given Work
Pull Request #1813: [wip] Ensures that one and only one README file is uploaded and that there is one or more files uploaded for any given Work

21 of 22 new or added lines in 4 files covered. (95.45%)

1 existing line in 1 file now uncovered.

3274 of 3415 relevant lines covered (95.87%)

223.46 hits per line

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

89.29
/app/controllers/works_wizard_controller.rb
1
# frozen_string_literal: true
2

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

6
# Controller to handle wizard Mode when editing an work
7
#
8
# The wizard flow is shown in the [mermaid diagram here](https://github.com/pulibrary/pdc_describe/blob/main/docs/wizard_flow.md).
9

10
class WorksWizardController < ApplicationController
1✔
11
  include ERB::Util
1✔
12
  around_action :rescue_aasm_error, only: [:validate, :new_submission_save]
1✔
13

14
  before_action :load_work, only: [:edit_wizard, :update_wizard, :attachment_select, :attachment_selected,
1✔
15
                                   :file_upload, :file_uploaded, :file_other, :review, :validate,
16
                                   :readme_select, :readme_uploaded, :readme_uploaded_payload]
17

18
  # GET /works/1/edit-wizard
19
  def edit_wizard
1✔
20
    @wizard_mode = true
14✔
21
    if validate_modification_permissions(work: @work,
14✔
22
                                         uneditable_message: "Can not edit work: #{@work.id} is not editable by #{current_user.uid}",
23
                                         current_state_message: "Can not edit work: #{@work.id} is not editable in current state by #{current_user.uid}")
24

25
      prepare_decorators_for_work_form(@work)
13✔
26
    end
27
  end
28

29
  # PATCH /works/1/update-wizard
30
  def update_wizard
1✔
31
    edit_helper(:edit_wizard, work_update_additional_path(@work))
12✔
32
  end
33

34
  # Prompt to select how to submit their files
35
  # GET /works/1/attachment_select
36
  def attachment_select; end
1✔
37

38
  # User selected a specific way to submit their files
39
  # POST /works/1/attachment_selected
40
  def attachment_selected
1✔
41
    @work.files_location = params["attachment_type"]
15✔
42
    @work.save!
15✔
43

44
    # create a directory for the work if the curator will need to move files by hand
45
    @work.s3_query_service.create_directory if @work.files_location != "file_upload"
15✔
46

47
    if params[:save_only] == "true"
15✔
48
      render :attachment_select
4✔
49
    else
50
      redirect_to file_location_url
11✔
51
    end
52
  end
53

54
  # Allow user to upload files directly
55
  # GET /works/1/file_upload
56
  def file_upload
1✔
57
    @work_decorator = WorkDecorator.new(@work, current_user)
8✔
58
  end
59

60
  # POST /works/1/upload-files-wizard (called via Uppy)
61
  def upload_files
1✔
62
    @work = Work.find(params[:id])
×
63
    upload_service = WorkUploadsEditService.new(@work, current_user)
×
64
    upload_service.update_precurated_file_list(params["files"], [])
×
65
  end
66

67
  # POST /works/1/file_upload
68
  def file_uploaded
1✔
69
    upload_service = WorkUploadsEditService.new(@work, current_user)
10✔
70
    # By the time we hit this endpoint files have been uploaded by Uppy submmitting POST requests
71
    # to /works/1/upload-files-wizard therefore we only need to delete files here and update the upload snapshot.
72
    @work = upload_service.snapshot_uppy_and_delete_files(deleted_files_param)
10✔
73

74
    prepare_decorators_for_work_form(@work)
9✔
75
    if params[:save_only] == "true"
9✔
76
      render :file_upload
2✔
77
    else
78
      redirect_to(work_review_path)
7✔
79
    end
80
  rescue => ex
81
    # Notice that we log the URL (rather than @work.doi) because sometimes we are getting a nil @work.
82
    # The URL will include the ID and might help us troubleshoot the issue further if it happens again.
83
    # See https://github.com/pulibrary/pdc_describe/issues/1801
84
    error_message = "Failed to update work snapshot, URL: #{request.url}: #{ex}"
1✔
85
    Rails.logger.error(error_message)
1✔
86
    Honeybadger.notify(error_message)
1✔
87
    flash[:notice] = "Failed to update work snapshot, work: #{@work&.doi}: #{ex}. Please contact rdss@princeton.edu for assistance."
1✔
88

89
    redirect_to work_file_upload_path(@work)
1✔
90
  end
91

92
  # Allow user to indicate where their files are located in the WWW
93
  # GET /works/1/file_other
94
  def file_other; end
1✔
95

96
  # GET /works/1/review
97
  # POST /works/1/review
98
  def review
1✔
99
    if request.method == "POST" || request.method == "PATCH"
15✔
100
      @work.location_notes = params["location_notes"]
7✔
101
      @work.save!
7✔
102
      if params[:save_only] == "true"
7✔
103
        render :file_other
2✔
104
      end
105
    end
106
  end
107

108
  # Validates that the work is ready to be approved
109
  # POST /works/1/validate-wizard
110
  # PATCH /works/1/validate-wizard
111
  def validate
1✔
112
    @work.submission_notes = params["submission_notes"]
13✔
113

114
    if params[:save_only] == "true"
13✔
115
      @work.save
2✔
116
      render :review
2✔
117
    else
118
      @work.complete_submission!(current_user)
11✔
119
      redirect_to work_complete_path(@work.id)
7✔
120
    end
121
  end
122

123
  # Show the user the form to select a readme
124
  # GET /works/1/readme_select
125
  def readme_select
1✔
126
    readme = Readme.new(@work, current_user)
14✔
127
    @readme = readme.file_name
14✔
128
  end
129

130
  # Hit when the user clicks "Save" or "Next" on the README upload process.
131
  # Notice that this does not really uploads the file, that happens in readme_uploaded_payload.
132
  # PATCH /works/1/readme_uploaded
133
  def readme_uploaded
1✔
134
    readme = Readme.new(@work, current_user)
12✔
135
    if params[:save_only] == "true"
12✔
136
      @readme = readme.file_name
2✔
137
      render :readme_select
2✔
138
    else
139
      redirect_to work_attachment_select_url(@work)
10✔
140
    end
141
  end
142

143
  def files_param
1✔
144
    params["files"]
6✔
145
  end
146

147
  # Uploads the README file, called by Uppy.
148
  # POST /works/1/readme-uploaded-payload
149
  def readme_uploaded_payload
1✔
150
    raise StandardError("Only one README file can be uploaded.") if files_param.empty?
2✔
151
    raise StandardError("Only one README file can be uploaded.") if files_param.length > 1
2✔
152

153
    readme_file = files_param.first
2✔
154
    readme = Readme.new(@work, current_user)
2✔
155

156
    readme_error = readme.attach(readme_file)
2✔
157
    if readme_error.nil?
2✔
158
      render plain: readme.file_name
1✔
159
    else
160
      # Tell Uppy there was an error uploading the README
161
      render plain: readme.file_name, status: :internal_server_error
1✔
162
    end
163
  end
164

165
  def file_location_url
1✔
166
    WorkMetadataService.file_location_url(@work)
24✔
167
  end
168
  helper_method :file_location_url
1✔
169

170
  def rescue_aasm_error
1✔
171
    yield
13✔
172
  rescue AASM::InvalidTransition => error
173
    message = message_from_aasm_error(aasm_error: error, work: @work)
4✔
174

175
    Honeybadger.notify("Invalid #{@work.current_transition}: #{error.message} errors: #{message}")
4✔
176
    transition_error_message = "We apologize, the following errors were encountered: #{message}."
4✔
177
    @errors = [transition_error_message]
4✔
178

179
    # redirect_to root_url, notice: transition_error_message
180
    redirect_aasm_error(transition_error_message)
4✔
181
  end
182

183
  private
1✔
184

185
    def edit_helper(view_name, redirect_url)
1✔
186
      if validate_modification_permissions(work: @work,
22✔
187
                                           uneditable_message: "Can not update work: #{@work.id} is not editable by #{current_user.uid}",
188
                                           current_state_message: "Can not update work: #{@work.id} is not editable in current state by #{current_user.uid}")
189
        prepare_decorators_for_work_form(@work)
22✔
190
        if WorkCompareService.update_work(work: @work, update_params:, current_user:)
22✔
191
          if params[:save_only] == "true"
21✔
192
            render view_name
3✔
193
          else
194
            redirect_to redirect_url
18✔
195
          end
196
        else
197
          render view_name, status: :unprocessable_entity
1✔
198
        end
199
      end
200
    end
201

202
    def load_work
1✔
203
      @work = Work.find(params[:id])
155✔
204
    end
205

206
    def patch_params
1✔
207
      return {} unless params.key?(:patch)
×
208

209
      params[:patch]
×
210
    end
211

212
    def pre_curation_uploads_param
1✔
213
      return if patch_params.nil?
×
214

215
      patch_params[:pre_curation_uploads]
×
216
    end
217

218
    def deleted_files_param
1✔
219
      deleted_count = (params.dig("work", "deleted_files_count") || "0").to_i
10✔
220
      (1..deleted_count).map { |i| params.dig("work", "deleted_file_#{i}") }.select(&:present?)
13✔
221
    end
222

223
    def readme_file_param
1✔
224
      return if patch_params.nil?
×
225

226
      patch_params[:readme_file]
×
227
    end
228

229
    def rescue_aasm_error_dis
1✔
UNCOV
230
      super
×
231
    rescue StandardError => generic_error
232
      redirect_to root_url, notice: "We apologize, an error was encountered: #{generic_error.message}. Please contact the PDC Describe administrators."
×
233
    end
234

235
    def redirect_aasm_error(transition_error_message)
1✔
236
      if @work.persisted?
4✔
237
        redirect_to edit_work_wizard_path(id: @work.id), notice: transition_error_message, params:
4✔
238
      else
239
        redirect_to work_create_new_submission_path(@work), notice: transition_error_message, params:
×
240
      end
241
    end
242
end
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