Class: StudiesController

Inherits:
ApplicationController show all
Includes:
AccessionHelper, Informatics::Globals, REXML
Defined in:
app/controllers/studies_controller.rb

Overview

rubocop:todo Metrics/ClassLength

Constant Summary

Constants included from FlashTruncation

FlashTruncation::STRING_OVERHEAD

Class Method Summary collapse

Instance Method Summary collapse

Methods included from AccessionHelper

#accessioning_enabled?, #permitted_to_accession?

Methods included from Informatics::Globals

#application, #application=, #defaults, #defaults=, #global_searchable_classes, #search_options

Methods inherited from ApplicationController

#block_api_access, #evil_parameter_hack!, #extract_header_info, #set_cache_disabled!

Methods included from AuthenticatedSystem

included

Methods included from FlashTruncation

#max_flash_size, #truncate_flash, #truncate_flash_array

Class Method Details

.role_helper(name, success_action, error_action) ⇒ Object

rubocop:todo Metrics/MethodLength



340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'app/controllers/studies_controller.rb', line 340

def self.role_helper(name, success_action, error_action) # rubocop:todo Metrics/AbcSize
  define_method(:"#{name}_role") do
    ActiveRecord::Base.transaction do
      @study = Study.find(params[:id])
      @user = User.find(params.require(:role).fetch(:user))

      if request.xhr?
        yield(@user, @study, params[:role][:authorizable_type].to_s)
        status, flash.now[:notice] = 200, "Role #{success_action}"
      else
        status, flash.now[:error] = 401, "A problem occurred while #{error_action} the role"
      end

      @roles = @study.roles.reload
      render partial: 'roles', status: status
    end
  end
end

Instance Method Details

#accessionObject



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'app/controllers/studies_controller.rb', line 240

def accession
  @study = Study.find(params[:id])
  return accessioning_not_enabled_redirect unless accessioning_enabled?

  # TODO: Y26-026 - Enforce accessioning permissions
  # return accession_permission_denied_redirect unless permitted_to_accession?(@study)

  handle_accession_action(
    notice: -> { "Accession number generated: #{@study.ebi_accession_number}" }
  ) do
    @study.validate_study_for_accessioning!
    accession_service = AccessionService.select_for_study(@study)
    accession_service.submit_study_for_user(@study, current_user)
  end
end

#accession_all_samplesvoid

This method returns an undefined value.

Accession all samples in the study.

If the study does not have an accession number, adds an error to the study and returns. Otherwise, iterates through each sample in the study and attempts to accession it, unless the sample already has an accession number. If an Accession::Error occurs for a sample, adds the error message to the study's errors.

NOTE: this does not check if the current user has permission to accession samples in this study



266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'app/controllers/studies_controller.rb', line 266

def accession_all_samples # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
  @study = Study.find(params[:id])
  return accessioning_not_enabled_redirect unless accessioning_enabled?

  # TODO: Y26-026 - Enforce accessioning permissions
  # return accession_permission_denied_redirect unless permitted_to_accession?(@study)

  unless @study.accession_number?
    flash[:error] = 'Please accession the study before accessioning samples'
    return redirect_to(study_path(@study))
  end
  unless @study.samples_accessionable?
    flash[:error] = 'Study cannot accession samples, see Study Accessioning tab for details'
    return redirect_to(study_path(@study))
  end

  @study.samples.find_each do |sample|
    next if sample.accession_number?

    begin
      Accession.accession_sample(sample, current_user)
    rescue Accession::Error => e
      @study.errors.add(:base, e.message)
    end
  end

  if @study.errors.any?
    flash[:error] = compile_accession_errors(@study.errors)
  else
    flash[:notice] = 'All of the samples in this study have been sent for accessioning. ' \
                     'Please check back in 5 minutes to confirm that accessioning was successful.'
  end
  redirect_to(study_path(@study))
end

#closeObject



175
176
177
178
179
180
181
182
183
184
# File 'app/controllers/studies_controller.rb', line 175

def close
  @study = Study.find(params[:id])
  authorize! :activate, @study
  comment = params[:comment]
  @study.comments.create(description: comment, user_id: current_user.id)
  @study.deactivate!
  @study.save
  flash[:notice] = "This study has been deactivated: #{comment}"
  redirect_to study_path(@study)
end

#collaboratorsObject



156
157
158
159
160
161
# File 'app/controllers/studies_controller.rb', line 156

def collaborators
  @study = Study.find(params[:id])
  @all_roles = Role.distinct.pluck(:name)
  @roles = Role.where(authorizable_id: @study.id, authorizable_type: 'Study')
  @users = User.order(:first_name)
end

#createObject

Create the Study from new with the details from its form. Redirect to the index page with a notice.



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'app/controllers/studies_controller.rb', line 83

def create # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
  ActiveRecord::Base.transaction do
    @study = Study.new(params['study'].merge(user: current_user))
    @study.save!
    current_user.grant_manager(@study)
    User.find(params[:study_owner_id]).grant_owner(@study) if params[:study_owner_id].present?
  end

  flash[:notice] = 'Your study has been created'
  respond_to do |format|
    format.html { redirect_to study_path(@study) }
    format.xml { render xml: @study, status: :created, location: @study }
    format.json { render json: @study, status: :created, location: @study }
  end
rescue ActiveRecord::RecordInvalid => e
  flash.now[:error] = 'Problems creating your new study'
  respond_to do |format|
    format.html { render action: 'new' }
    format.xml { render xml: @study.errors, status: :unprocessable_entity }
    format.json { render json: @study.errors, status: :unprocessable_entity }
  end
end

#dac_accessionObject



301
302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'app/controllers/studies_controller.rb', line 301

def dac_accession
  @study = Study.find(params[:id])
  return accessioning_not_enabled_redirect unless accessioning_enabled?

  # TODO: Y26-026 - Enforce accessioning permissions
  # return accession_permission_denied_redirect unless permitted_to_accession?(@study)

  handle_accession_action(
    notice: -> { "Accession number generated: #{@study.dac_accession_number}" }
  ) do
    accession_service = AccessionService.select_for_study(@study)
    accession_service.submit_dac_for_user(@study, current_user)
  end
end

#editObject



75
76
77
78
79
# File 'app/controllers/studies_controller.rb', line 75

def edit
  @study = Study.find(params[:id])
  flash.now[:warning] = @study.warnings if @study.warnings.present?
  @users = User.all
end

#followObject

rubocop:todo Metrics/AbcSize



163
164
165
166
167
168
169
170
171
172
173
# File 'app/controllers/studies_controller.rb', line 163

def follow # rubocop:todo Metrics/AbcSize
  @study = Study.find(params[:id])
  if current_user.follower_of?(@study)
    current_user.remove_role 'follower', @study
    flash[:notice] = "You have stopped following the '#{@study.name}' study."
  else
    current_user.grant_follower(@study)
    flash[:notice] = "You are now following the '#{@study.name}' study."
  end
  redirect_to study_information_path(@study)
end

#handle_accession_action(notice:) ⇒ Object

rubocop:todo Metrics/AbcSize, Metrics/MethodLength



222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'app/controllers/studies_controller.rb', line 222

def handle_accession_action(notice:) # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
  yield
  flash[:notice] = notice.call
  redirect_to(study_path(@study))
rescue ActiveRecord::RecordInvalid => e
  flash.now[:error] = 'Please fill in the required fields'
  render(action: :edit)
rescue AccessionService::NumberNotRequired => e
  flash[:warning] = e.message || 'An accession number is not required for this study'
  redirect_to(study_path(@study))
rescue AccessionService::NumberNotGenerated => e
  flash[:warning] = "No accession number was generated: #{e.message}"
  redirect_to(study_path(@study))
rescue AccessionService::AccessionServiceError => e
  flash[:error] = e.message
  redirect_to(edit_study_path(@study))
end

#indexObject



43
44
45
46
47
48
49
50
51
# File 'app/controllers/studies_controller.rb', line 43

def index
  # Please do not user current_user outside this block, you kill the API calls
  setup_studies_from_scope(@exclude_nested_resource)
  respond_to do |format|
    format.html
    format.xml { render(action: (@exclude_nested_resource ? 'index' : 'index_deprecated_xml')) }
    format.json { render json: Study.all.to_json }
  end
end

#newObject



70
71
72
73
# File 'app/controllers/studies_controller.rb', line 70

def new
  @study = Study.new
  respond_to { |format| format.html }
end

#openObject



186
187
188
189
190
191
192
193
# File 'app/controllers/studies_controller.rb', line 186

def open
  @study = Study.find(params[:id])
  authorize! :activate, @study
  @study.activate!
  @study.save
  flash[:notice] = 'This study has been activated'
  redirect_to study_path(@study)
end

#policy_accessionObject



316
317
318
319
320
321
322
323
324
325
326
327
328
329
# File 'app/controllers/studies_controller.rb', line 316

def policy_accession
  @study = Study.find(params[:id])
  return accessioning_not_enabled_redirect unless accessioning_enabled?

  # TODO: Y26-026 - Enforce accessioning permissions
  # return accession_permission_denied_redirect unless permitted_to_accession?(@study)

  handle_accession_action(
    notice: -> { "Accession number generated: #{@study.policy_accession_number}" }
  ) do
    accession_service = AccessionService.select_for_study(@study)
    accession_service.submit_policy_for_user(@study, current_user)
  end
end

#projectsObject



364
365
366
367
# File 'app/controllers/studies_controller.rb', line 364

def projects
  @study = Study.find(params[:id])
  @projects = @study.projects.page(params[:page])
end

#propertiesObject



146
147
148
149
150
151
152
153
154
# File 'app/controllers/studies_controller.rb', line 146

def properties
  @study = Study.find(params[:id])

  respond_to do |format|
    format.html
    format.xml
    format.json { render json: @study.to_json }
  end
end

#sample_manifestsObject



369
370
371
372
# File 'app/controllers/studies_controller.rb', line 369

def sample_manifests
  @study = Study.find(params[:id])
  @sample_manifests = @study.sample_manifests.page(params[:page]).order(id: :desc)
end

#setup_studies_from_scope(exclude_nested_resource = false) ⇒ Object

rubocop:todo Metrics/AbcSize



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'app/controllers/studies_controller.rb', line 19

def setup_studies_from_scope(exclude_nested_resource = false) # rubocop:todo Metrics/AbcSize
  if logged_in? && (not exclude_nested_resource)
    @alternatives = [
      'interesting',
      'followed',
      'managed & active',
      'managed & inactive',
      'pending',
      'pending ethical approval',
      'contaminated with human dna',
      'remove x and autosomes',
      'active',
      'inactive',
      'collaborations',
      'all'
    ]
    @studies = studies_from_scope(@alternatives[params[:scope].to_i])
  elsif params[:project_id] && !(project = Project.find(params[:project_id])).nil?
    @studies = project.studies.newest_first.includes(:user, :roles)
  else
    @studies = Study.newest_first.with_user_included.with_related_users_included
  end
end

#showObject



60
61
62
63
64
65
66
67
68
# File 'app/controllers/studies_controller.rb', line 60

def show
  @study = Study.find(params[:id])
  flash.keep
  respond_to do |format|
    format.html { redirect_to study_information_path(@study) }
    format.xml { render layout: false }
    format.json { render json: @study.to_json }
  end
end

#show_accessionObject



195
196
197
198
199
200
201
202
# File 'app/controllers/studies_controller.rb', line 195

def show_accession
  @study = Study.find(params[:id])
  respond_to do |format|
    accession_service = AccessionService.select_for_study(@study)
    xml_text = accession_service.accession_study_xml(@study)
    format.xml { render(xml: xml_text) }
  end
end

#show_dac_accessionObject



213
214
215
216
217
218
219
220
# File 'app/controllers/studies_controller.rb', line 213

def show_dac_accession
  @study = Study.find(params[:id])
  respond_to do |format|
    accession_service = AccessionService.select_for_study(@study)
    xml_text = accession_service.accession_dac_xml(@study)
    format.xml { render(xml: xml_text) }
  end
end

#show_policy_accessionObject



204
205
206
207
208
209
210
211
# File 'app/controllers/studies_controller.rb', line 204

def show_policy_accession
  @study = Study.find(params[:id])
  respond_to do |format|
    accession_service = AccessionService.select_for_study(@study)
    xml_text = accession_service.accession_policy_xml(@study)
    format.xml { render(xml: xml_text) }
  end
end

#sraObject



331
332
333
# File 'app/controllers/studies_controller.rb', line 331

def sra
  @study = Study.find(params[:id])
end

#stateObject



335
336
337
# File 'app/controllers/studies_controller.rb', line 335

def state
  @study = Study.find(params[:id])
end

#study_listObject



53
54
55
56
57
58
# File 'app/controllers/studies_controller.rb', line 53

def study_list
  return redirect_to(studies_path) unless request.xhr?

  setup_studies_from_scope
  render partial: 'study_list', locals: { studies: @studies.with_related_owners_included }
end

#study_reportsObject



379
380
381
382
# File 'app/controllers/studies_controller.rb', line 379

def study_reports
  @study = Study.find(params[:id])
  @study_reports = StudyReport.for_study(@study).page(params[:page]).order(id: :desc)
end

#study_statusObject

rubocop:enable Metrics/MethodLength



133
134
135
136
137
138
139
140
141
142
143
144
# File 'app/controllers/studies_controller.rb', line 133

def study_status
  @study = Study.find(params[:id])
  authorize! :activate, @study

  if @study.inactive? || @study.pending?
    @study.activate!
  elsif @study.active?
    @study.deactivate!
  end
  flash[:notice] = 'Study status was updated successfully'
  redirect_to study_path(@study)
end

#suppliersObject



374
375
376
377
# File 'app/controllers/studies_controller.rb', line 374

def suppliers
  @study = Study.find(params[:id])
  @suppliers = @study.suppliers.page(params[:page])
end

#updateObject

rubocop:todo Metrics/MethodLength



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'app/controllers/studies_controller.rb', line 107

def update # rubocop:todo Metrics/AbcSize
  @study = Study.find(params[:id])

  ActiveRecord::Base.transaction do
    @study.update!(params[:study])
    if params[:study_owner_id].present?
      owner = User.find(params[:study_owner_id])
      unless owner.owner_of?(@study)
        @study.owners.first.remove_role('owner', @study) if @study.owners.size == 1
        owner.grant_owner(@study)
      end
    end

    flash[:notice] = 'Your study has been updated'

    redirect_to study_path(@study)
  end
rescue ActiveRecord::RecordInvalid => e
  # don't use @study.errors.map(&:to_s) because it throws an exception when within a rescue block
  Rails.logger.warn "Failed to update attributes: #{@study.errors.map { |error| error.to_s }}" # rubocop:disable Style/SymbolProc
  flash.now[:error] = 'Failed to update attributes for study!'
  render action: 'edit', id: @study.id
end