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

pulibrary / tigerdata-app / e130d700-992b-4a2c-b918-1137df0404ca

29 Jul 2025 08:58PM UTC coverage: 75.423% (-5.2%) from 80.666%
e130d700-992b-4a2c-b918-1137df0404ca

push

circleci

web-flow
Added error handling to the request to project workflow (#1656)

* Added error handling

* Rubocop

* Adjust tests to match the new error handling

* Make the display for errors a little nicer

* Minor tweaks

* Set a default value for the CI environment

* Undo change

* Add a test for the request.approve

* Rubocop

* Marked a few more tests as integration tests

* Marked a bunch of tests as integration since they create projects in Mediaflux

12 of 17 new or added lines in 4 files covered. (70.59%)

157 existing lines in 19 files now uncovered.

2274 of 3015 relevant lines covered (75.42%)

344.0 hits per line

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

75.68
/app/controllers/projects_controller.rb
1
# frozen_string_literal: true
2
class ProjectsController < ApplicationController
1✔
3

4
  before_action :set_breadcrumbs
1✔
5
  before_action :authenticate_user!
1✔
6

7
  def new
1✔
8
    add_breadcrumb("New Project Request")
16✔
9
    return build_new_project if current_user.eligible_sponsor?
16✔
10

11
    redirect_to dashboard_path
2✔
12
  end
13

14
  def project_params
1✔
15
    params.dup
×
16
  end
17

18
  def create
1✔
19
    metadata_params = params.dup
12✔
20
    metadata_params[:status] = Project::PENDING_STATUS
12✔
21
    metadata_params[:created_by] = current_user.uid
12✔
22
    metadata_params[:created_on] = Time.current.in_time_zone("America/New_York").iso8601
12✔
23
    project_metadata = ProjectMetadata.new_from_params(metadata_params)
12✔
24

25
    build_new_project # calling private method to build a new project and set a class variable @project
12✔
26
    project.create!(initial_metadata: project_metadata, user: current_user)
12✔
27
    if project.metadata_model.project_id != nil
12✔
28
      begin
29
        mailer = TigerdataMailer.with(project_id: project.id)
12✔
30
        message_delivery = mailer.project_creation
12✔
31
        message_delivery.deliver_later
12✔
32

33
        redirect_to project_confirmation_path(project)
11✔
34
      rescue StandardError => mailer_error
35
        raise(TigerData::MailerError, mailer_error)
2✔
36
      end
37
    else
38
      render :new
×
39
    end
40
  rescue TigerData::MailerError => mailer_error
41
    logger_message = "Error encountered creating the project #{project.id} as user #{current_user.email}"
2✔
42
    Rails.logger.error(logger_message)
2✔
43
    honeybadger_context = {
44
      current_user_email: current_user.email,
2✔
45
      project_id: project.id,
46
      project_metadata: project.metadata
47
    }
48
    Honeybadger.notify(mailer_error, context: honeybadger_context)
2✔
49

50
    error_message = "We are sorry, while the project was successfully created, an error was encountered which prevents the delivery of an e-mail message confirming this. Please know that this error has been logged, and shall be reviewed by members of RDSS."
2✔
51
    flash[:notice] = error_message
2✔
52

53
    render :new
2✔
54
  rescue StandardError => error
55
    logger_message = if project.persisted?
×
56
                      "Error encountered creating the project #{project.id} as user #{current_user.email}"
×
57
                     else
58
                      "Error encountered creating the project #{metadata_params[:title]} as user #{current_user.email}"
×
59
                     end
60
    Rails.logger.error(logger_message)
×
61
    honeybadger_context = {
62
      current_user_email: current_user.email,
×
63
      project_id: project.id,
64
      project_metadata: project.metadata
65
    }
66
    Honeybadger.notify(error, context: honeybadger_context)
×
67

68
    error_message = "We are sorry, the project was not successfully created, and an error was encountered which prevents the delivery of an e-mail message confirming this. Please know that this error has been logged, and shall be reviewed by members of RDSS promptly."
×
69

70
    flash[:notice] = error_message
×
71
    render :new
×
72
  end
73

74
  def details
1✔
75
    return if project.blank?
28✔
76

77
    add_breadcrumb(project.title, project_path)
27✔
78
    add_breadcrumb("Details")
27✔
79

80
    @departments = project.departments.join(", ")
27✔
81
    @project_metadata = project.metadata_model
27✔
82

83
    @data_sponsor = User.find_by(uid: @project_metadata.data_sponsor)
27✔
84
    @data_manager = User.find_by(uid: @project_metadata.data_manager)
27✔
85

86
    read_only_uids = @project_metadata.ro_users
27✔
87
    data_read_only_users = read_only_uids.map { |uid| ReadOnlyUser.find_by(uid:) }.reject(&:blank?)
43✔
88

89
    read_write_uids = @project_metadata.rw_users
27✔
90
    data_read_write_users = read_write_uids.map { |uid| User.find_by(uid:) }.reject(&:blank?)
39✔
91

92
    unsorted_data_users = data_read_only_users + data_read_write_users
27✔
93
    sorted_data_users = unsorted_data_users.sort_by { |u| u.family_name || u.uid }
55✔
94
    @data_users = sorted_data_users.uniq { |u| u.uid }
47✔
95
    user_model_names = @data_users.map(&:display_name_safe)
27✔
96
    @data_user_names = user_model_names.join(", ")
27✔
97

98
    @provenance_events = project.provenance_events.where.not(event_type: ProvenanceEvent::STATUS_UPDATE_EVENT_TYPE)
27✔
99

100
    @project_eligible_to_edit = true if project.status == Project::APPROVED_STATUS && eligible_editor?
27✔
101

102
    @project_metadata = @project.metadata
27✔
103
    @project_id = @project_metadata[:project_id] || {}
27✔
104
    @storage_capacity = @project_metadata[:storage_capacity]
27✔
105
    @size = @storage_capacity[:size]
27✔
106
    @unit = @storage_capacity[:unit]
27✔
107

108
    @requested_size = @size[:requested]
27✔
109
    @requested_unit = @unit[:requested]
27✔
110

111
    @approved_size = @size[:approved]
27✔
112
    @approved_unit = @unit[:approved]
27✔
113

114
    @storage_expectations = @project_metadata[:storage_performance_expectations]
27✔
115
    @requested_storage_expectations = @storage_expectations[:requested]
27✔
116
    @approved_storage_expectations = @storage_expectations[:approved]
27✔
117

118
    @project_purpose = @project_metadata[:project_purpose]
27✔
119

120

121
    @project_session = "details"
27✔
122

123
    respond_to do |format|
27✔
124
      format.html do
27✔
125
        @project = ProjectShowPresenter.new(project)
25✔
126
      end
127
      format.json do
27✔
128
        render json: project.to_json
2✔
129
      end
130
      format.xml do
27✔
131
        render xml: project.to_xml
×
132
      end
133
    end
134
  end
135

136
  def edit
1✔
137
    add_breadcrumb(project.title, project_path)
14✔
138
    add_breadcrumb("Edit")
14✔
139
    project
14✔
140
    if project.metadata_model.status != Project::APPROVED_STATUS
14✔
141
      flash[:notice] = "Pending projects can not be edited."
1✔
142
      redirect_to project
1✔
143
    elsif project.metadata_model.status == Project::APPROVED_STATUS && !eligible_editor? #check if the current user is a sponsor or a manager
13✔
144
      flash[:notice] = "Only data sponsors and data managers can revise this project."
2✔
145
      redirect_to project
2✔
146
    end
147
  end
148

149
  def update
1✔
150
    @project = Project.find(params[:id])
4✔
151
    #Approve action
152
    if params.key?("approved")
4✔
UNCOV
153
      @project.metadata_model.update_with_params(params, current_user)
×
UNCOV
154
      @project.approve!(current_user:)
×
155
    end
156

157
    #Edit action
158
    if params.key?("title")
4✔
159
      @project.metadata_model.status = @project.metadata_model.status || Project::PENDING_STATUS
4✔
160
      @project.metadata_model.update_with_params(params, current_user)
4✔
161
    end
162

163
    # @todo ProjectMetadata should be refactored to implement ProjectMetadata.valid?(updated_metadata)
164
    if project.save and params.key?("approved")
4✔
UNCOV
165
      redirect_to project_approval_received_path(@project)
×
166
    elsif project.save and params.key?("title")
4✔
167
      redirect_to project_revision_confirmation_path(@project)
4✔
168
    else
169
      render :edit
×
170
    end
171
  end
172

173
  def index
1✔
174
    if current_user.eligible_sysadmin?
5✔
175
      @projects = Project.all
1✔
176
    else
177
      flash[:alert] = I18n.t(:access_denied)
4✔
178
      redirect_to dashboard_path
4✔
179
    end
180
  end
181

182
  def confirmation; end
1✔
183
  def revision_confirmation; end
1✔
184

185
  def show
1✔
186

187
    return if project.blank?
16✔
188
    add_breadcrumb(project.title, project_path)
15✔
189
    add_breadcrumb("Contents")
15✔
190

191
    @latest_completed_download = current_user.user_requests.where(project_id: @project.id, state: "completed").order(:completion_time).last
15✔
192
    @storage_usage = project.storage_usage(session_id: current_user.mediaflux_session)
15✔
193
    @storage_capacity = project.storage_capacity(session_id: current_user.mediaflux_session)
15✔
194

195
    @num_files = project.asset_count(session_id: current_user.mediaflux_session)
15✔
196

197
    @file_list = project.file_list(session_id: current_user.mediaflux_session, size: 100)
15✔
198
    @files = @file_list[:files]
15✔
199
    @files.sort_by!(&:path)
15✔
200
    @project = ProjectShowPresenter.new(project)
15✔
201

202
    @project_session = "content"
15✔
203
    respond_to do |format|
15✔
204
      format.html { render }
29✔
205
      format.xml { render xml: @project.to_xml }
16✔
206
    end
207
  end
208

209
  # GET "projects/:id/:id-mf"
210
  #
211
  # This action is used to render the mediaflux metadata for a project.
212
  def show_mediaflux
1✔
213
    project_id = params[:id]
1✔
214
    project = Project.find(project_id)
1✔
215
    if project.mediaflux_id == 0
1✔
NEW
216
      flash[:alert] = "Project has not been created in Mediaflux"
×
217
      redirect_to project_path(project_id)
×
218
    else
219
      respond_to do |format|
1✔
220
        format.xml do
1✔
221
          render xml: project.mediaflux_meta_xml(user: current_user)
1✔
222
        end
223
      end
224
    end
225
  end
226

227
  def project_job_service
1✔
228
    @project_job_service ||= ProjectJobService.new(project:)
×
229
  end
230

231
  def list_contents
1✔
232
    return if project.blank?
1✔
233

234
    project_job_service.list_contents_job(user: current_user)
×
235

236
    json_response = {
237
      message: "File list for \"#{project.title}\" is being generated in the background. A link to the downloadable file list will be available in the \"Recent Activity\" section of your dashboard when it is available. You may safely navigate away from this page or close this tab."
×
238
    }
239
    render json: json_response
×
240
  rescue => ex
241
    message = "Error producing document list (project id: #{project&.id}): #{ex.message}"
×
242
    Rails.logger.error(message)
×
243
    Honeybadger.notify(message)
×
244
    render json: { message: "Document list could not be generated." }
×
245
  end
246

247
  def file_list_download
1✔
248
    job_id = params[:job_id]
×
249
    user_request = FileInventoryRequest.where(job_id:job_id).first
×
250
    if user_request.nil?
×
251
      # TODO: handle error
252
      redirect_to "/"
×
253
    else
254
      filename = user_request.output_file
×
255
      send_data File.read(filename), type: "text/plain", filename: "filelist.csv", disposition: "attachment"
×
256
    end
257
  end
258

259
  def approve
1✔
260
    if current_user.eligible_sysadmin?
3✔
UNCOV
261
      add_breadcrumb(project.title, project_path)
×
UNCOV
262
      add_breadcrumb("Approval Settings", project_approve_path)
×
UNCOV
263
      add_breadcrumb("Edit")
×
UNCOV
264
      project
×
UNCOV
265
      @departments = project.departments.join(", ")
×
UNCOV
266
      @project_metadata = project.metadata
×
UNCOV
267
      sponsor_uid = @project_metadata[:data_sponsor]
×
UNCOV
268
      @data_sponsor = User.find_by(uid: sponsor_uid)
×
UNCOV
269
      @provenance_events = project.provenance_events.where.not(event_type: ProvenanceEvent::STATUS_UPDATE_EVENT_TYPE)
×
270

UNCOV
271
      @title = @project_metadata["title"]
×
272
    else
273
      redirect_to dashboard_path
3✔
274
    end
275
  end
276

277
  private
1✔
278

279
    def build_new_project
1✔
280
      @project ||= Project.new
26✔
281
    end
282

283
    def project
1✔
284
      @project ||= begin
416✔
285
        project = Project.find(params[:id])
59✔
286
        if project.user_has_access?(user: current_user)
59✔
287
          project
56✔
288
        else
289
          flash[:alert] = I18n.t(:access_denied)
3✔
290
          redirect_to dashboard_path
3✔
291
          nil
3✔
292
        end
293
      end
294
    end
295

296
    def eligible_editor?
1✔
297
      return true if current_user.eligible_sponsor? or current_user.eligible_manager?
20✔
298
    end
299

300
    def shared_file_location(filename)
1✔
301
      raise "Shared location is not configured" if Rails.configuration.mediaflux["shared_files_location"].blank?
×
302
      location = Pathname.new(Rails.configuration.mediaflux["shared_files_location"])
×
303
      location.join(filename).to_s
×
304
    end
305

306
    def set_breadcrumbs
1✔
307
      add_breadcrumb("Dashboard",dashboard_path)
116✔
308
    end
309
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

© 2026 Coveralls, Inc