sanger/sequencescape

View on GitHub
app/controllers/npg_actions/assets_controller.rb

Summary

Maintainability
A
25 mins
Test Coverage
A
100%
# frozen_string_literal: true

# Takes QC decisions on lanes from NPG and records the
# information in Sequencescape, passing the requests and creating
# events as required.
class NpgActions::AssetsController < ApplicationController
  # Raised if an action is performed which contradicts a previous one
  NPGActionInvalid = Class.new(StandardError)

  before_action :login_required, except: %i[pass fail]
  before_action :find_asset, only: %i[pass fail]
  before_action :find_request, only: %i[pass fail]
  before_action :find_last_event, only: %i[pass fail]
  before_action :qc_information, only: %i[pass fail]

  rescue_from(ActiveRecord::RecordNotFound, with: :rescue_error)
  rescue_from(NPGActionInvalid, ActionController::ParameterMissing, with: :rescue_error_bad_request)

  def fail
    action_for_qc_state('fail')
  end

  def pass
    action_for_qc_state('pass')
  end

  private

  def action_for_qc_state(state) # rubocop:todo Metrics/MethodLength
    ActiveRecord::Base.transaction do
      if @last_event.present?
        # If we already have an event we check to see its state. If it matches,
        # we just continue to rendering, otherwise we blow up.
        raise NPGActionInvalid, 'NPG user run this action. Please, contact USG' if @last_event.family != state
      else
        generate_events(state)
      end

      respond_to { |format| format.any { render template: 'assets/show', formats: [:xml] } }
    end
  end

  def generate_events(state)
    state_str = "#{state}ed"
    batch = @request.batch || raise(ActiveRecord::RecordNotFound, 'Unable to find a batch for the Request')

    @asset.set_qc_state(state_str)

    @asset.events.create_state_update!(qc_information[:message] || 'No reason given')

    message = "#{state}ed manual QC".capitalize
    EventSender.send_state_event(state, @request, '', message, '', 'npg')

    batch.npg_set_state

    BroadcastEvent::SequencingComplete.create!(seed: @asset, properties: { result: state_str })
  end

  def find_asset
    @asset = Lane.find(params[:asset_id])
  end

  def find_request
    # select any non-cancelled requests
    requests = @asset.requests_as_target.not_cancelled

    # throw exception if no valid requests found
    unless requests.one?
      raise ActiveRecord::RecordNotFound,
            "Unable to identify a suitable single active request for Asset: #{params[:asset_id]}"
    end

    # eager load the request to include the batch and all requests in the batch
    @request = requests.includes(batch: { requests: :asset }).first
  end

  def find_last_event
    @last_event = Event.family_pass_and_fail.npg_events(@request.id).first
  end

  def qc_information
    params.require(:qc_information).permit(:message)
  end

  def rescue_error(exception)
    render xml: "<error><message>#{exception.message}</message></error>", status: :not_found
  end

  def rescue_error_bad_request(exception)
    render xml: "<error><message>#{exception.message.split("\n").first}</message></error>", status: :bad_request
  end
end