Class: AccessionService

Inherits:
Object
  • Object
show all
Includes:
REXML
Defined in:
app/models/accession_service.rb

Overview

The EBI operates two key AccessionServices

ENA: Mostly non-human data, provides open access to uploaded data EGA: Mostly for human data, provides managed access to uploaded data

We also submit information to ArrayExpress, but this happens indirectly via the accession services above. Accessioning involves submitting metadata to an external database as XML files. This data receives a unique 'accession number' which we store in the database. These accession numbers can then be used in publications to allow external researchers access to the metadata.

Accessionables

Accessionable::Sample Represents information about the sample, maps to a Sequencescape Sample. Accessionable::Study Represents information about the study. Indicates WHY the samples have been sequenced. Maps to a Sequencescape Study. Accessionable::Submission Wrapper object required by the submission service. We use one per accessionable. The following are associated with EGA studies. Accessionable::Dac Data access committee. Information about who to contact to gain access to the data. (EGA) Accessionable::Policy Details about how the data may be used. (EGA)

Accessioning of samples has been partially migrated to 'a separate accession library'

Defined Under Namespace

Classes: AccessionedFile

Constant Summary collapse

AccessionServiceError =

Define custom error classes for the AccessionService

Class.new(StandardError)
AccessioningDisabledError =
Class.new(AccessionServiceError)
AccessionValidationFailed =
Class.new(AccessionServiceError)
NumberNotRequired =
Class.new(AccessionServiceError)
NumberNotGenerated =
Class.new(AccessionServiceError)
CENTER_NAME =

TODO: [xxx] use confing file

'SC'
PROTECT =
'protect'
HOLD =
'hold'

Instance Method Summary collapse

Instance Method Details

#accession_dac_xml(study) ⇒ Object



186
187
188
# File 'app/models/accession_service.rb', line 186

def accession_dac_xml(study)
  Accessionable::Dac.new(study).xml
end

#accession_policy_xml(study) ⇒ Object



181
182
183
184
# File 'app/models/accession_service.rb', line 181

def accession_policy_xml(study)
  policy = Accessionable::Policy.new(study)
  policy.xml
end

#accession_sample_xml(sample) ⇒ Object



177
178
179
# File 'app/models/accession_service.rb', line 177

def accession_sample_xml(sample)
  Accessionable::Sample.new(sample).xml
end

#accession_study_xml(study) ⇒ Object



173
174
175
# File 'app/models/accession_service.rb', line 173

def accession_study_xml(study)
  Accessionable::Study.new(study).xml
end

#dac_visibility(_study) ⇒ Object



202
203
204
# File 'app/models/accession_service.rb', line 202

def dac_visibility(_study)
  PROTECT
end

#policy_visibility(_study) ⇒ Object



198
199
200
# File 'app/models/accession_service.rb', line 198

def policy_visibility(_study)
  PROTECT
end

#private?Boolean

Returns:

  • (Boolean)


206
207
208
# File 'app/models/accession_service.rb', line 206

def private?
  false
end

#providerObject



47
48
# File 'app/models/accession_service.rb', line 47

def provider
end

#sample_visibility(_sample) ⇒ Object



190
191
192
# File 'app/models/accession_service.rb', line 190

def sample_visibility(_sample)
  PROTECT
end

#study_visibility(_study) ⇒ Object



194
195
196
# File 'app/models/accession_service.rb', line 194

def study_visibility(_study)
  PROTECT
end

#submit(user, *accessionables) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'app/models/accession_service.rb', line 70

def submit(user, *accessionables)
  ActiveRecord::Base.transaction do
    submission = Accessionable::Submission.new(self, user, *accessionables)

    errors = submission.all_accessionables.map(&:errors).flatten

    raise AccessionServiceError, errors.join("\n") unless errors.empty?

    files = [] # maybe not necessary, but just to be sure that the tempfile still exists when they are sent
    begin
      xml_result =
        post_files(
          submission.all_accessionables.map do |acc|
            file = Tempfile.open("#{acc.schema_type}_file")
            files << file
            file.puts(acc.xml)
            file.open # reopen for read

            Rails.logger.debug { file.each_line.to_a.join("\n") }

            { name: acc.schema_type.upcase, local_name: file.path, remote_name: acc.file_name }
          end
        )
      Rails.logger.debug { xml_result }
      if xml_result.match?(/(Server error|Auth required|Login failed)/)
        raise AccessionServiceError, "EBI Server Error. Could not get accession number: #{xml_result}"
      end

      xmldoc = Document.new(xml_result)
      success = xmldoc.root.attributes['success']
      accession_numbers = []

      # for some reasons, ebi doesn't give us back a accession number for the submission if it's a MODIFY action
      # therefore, we should be ready to get one or not
      number_generated = true
      case success
      when 'true'
        # extract and update accession numbers
        accession_number =
          submission.all_accessionables.each do |acc|
            accession_number = acc.extract_accession_number(xmldoc)
            if accession_number
              acc.update_accession_number!(user, accession_number)
              accession_numbers << accession_number
            else
              # error only, if one of the expected accessionable didn't get a AN
              # We don't care about the submission
              number_generated = false if accessionables.include?(acc)
            end
            ae_an = acc.extract_array_express_accession_number(xmldoc)
            acc.update_array_express_accession_number!(ae_an) if ae_an
          end

        raise NumberNotGenerated, 'Service gave no numbers back' unless number_generated
      when 'false'
        errors = xmldoc.root.elements.to_a('//ERROR').map(&:text)
        current_error = errors.first
        message = "Current error is: '#{current_error}'"
        more_messages = "There are #{errors.length - 1} more errors." if errors.many?
        raise AccessionServiceError,
              ['Could not get accession number. Error in submitted data:', $!.to_s, message,
               more_messages].compact.join(' ')
      else
        raise AccessionServiceError, "Could not get accession number. Error in submitted data: #{$!}"
      end
    ensure
      files.each(&:close) # not really necessary but recommended
    end
  end

  accessionables.map(&:accession_number)
end

#submit_dac_for_user(_study, _user) ⇒ Object

Raises:



169
170
171
# File 'app/models/accession_service.rb', line 169

def submit_dac_for_user(_study, _user)
  raise NumberNotRequired, 'No need to'
end

#submit_sample_for_user(sample, user) ⇒ Object



143
144
145
146
147
148
# File 'app/models/accession_service.rb', line 143

def submit_sample_for_user(sample, user)
  # TODO: commented out line as not used without error handling
  # ebi_accession_number = sample.sample_metadata.sample_ebi_accession_number

  submit(user, Accessionable::Sample.new(sample))
end

#submit_study_for_user(study, user) ⇒ Object

Raises:



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'app/models/accession_service.rb', line 150

def submit_study_for_user(study, user)
  raise NumberNotRequired, 'An accession number is not required for this study' unless study.accession_required?

  # Flag set in the deployment project to allow per-environment enabling of accessioning
  unless configatron.accession_samples
    raise AccessionService::AccessioningDisabledError, 'Accessioning is not enabled in this environment.'
  end

  # TODO: check error
  # raise AccessionServiceError, "Cannot generate accession number: #{ sampledata[:error] }" if sampledata[:error]

  # TODO: commented as not used without error handling
  # ebi_accession_number = study.study_metadata.study_ebi_accession_number

  # raise NumberNotGenerated, 'No need to' if not ebi_accession_number.blank? and not /ER/.match(ebi_accession_number)

  submit(user, Accessionable::Study.new(study))
end