diff --git a/app/controllers/nih_tables_controller.rb b/app/controllers/nih_tables_controller.rb index 5013aa343..b1de0d0e3 100644 --- a/app/controllers/nih_tables_controller.rb +++ b/app/controllers/nih_tables_controller.rb @@ -1,41 +1,37 @@ class NihTablesController < ApplicationController def show - samples_report = SamplesReport.find(params[:id]) - return unless authorize_resource(samples_report, READ_SAMPLES_REPORT) + @samples_report = SamplesReport.find(params[:id]) + return unless authorize_resource(@samples_report, READ_SAMPLES_REPORT) - purpose = samples_report.samples[0].box.purpose - zip_file = create_zip_file(samples_report.name) - - if purpose == "LOD" - add_lod_table(zip_file) - elsif purpose == "Challenge" - add_challenge_table(zip_file) - end - - zip_file.close - - send_zip_file(zip_file, samples_report.name) + zip_data = create_zip_file + send_data zip_data.read, type: 'application/zip', filename: "#{@samples_report.name}_nih_tables.zip" end private - def create_zip_file(filename) - zip_file = Tempfile.new("#{filename}_nih_tables.zip") - Zip::File.open(zip_file.path, Zip::File::CREATE) do |zip| - zip.add("Instructions.txt", Rails.root.join('public/templates/Instructions.txt')) + def create_zip_file + purpose = @samples_report.samples[0].box.purpose + + zip_stream = Zip::OutputStream.write_buffer do |stream| + # Read public/templates/Instructions.txt contents and write to zip + stream.put_next_entry('Instructions.txt') + stream.write(File.read(Rails.root.join('public/templates/Instructions.txt'))) + + add_nih_table('samples', stream) + add_nih_table('results', stream) + + if purpose == "LOD" + #add_nih_table('lod', stream) + elsif purpose == "Challenge" + #add_nih_table('challenge', stream) + end end - zip_file + zip_stream.rewind + zip_stream end - - def add_lod_table(zip_file) - # TODO: Add the LOD table to the zip file - end - - def add_challenge_table(zip_file) - # TODO: Add the Challenge table to the zip file - end - - def send_zip_file(zip_file, filename) - send_file zip_file.path, type: 'application/zip', filename: "#{filename}_nih_tables.zip" + + def add_nih_table(table_name, stream) + stream.put_next_entry("#{@samples_report.name}_#{table_name}.csv") + stream.write(render_to_string('samples_reports/nih_'+table_name, formats: :csv)) end end \ No newline at end of file diff --git a/app/views/samples_reports/nih_results.csv.csvbuilder b/app/views/samples_reports/nih_results.csv.csvbuilder new file mode 100644 index 000000000..756aaa93c --- /dev/null +++ b/app/views/samples_reports/nih_results.csv.csvbuilder @@ -0,0 +1,23 @@ +csv << [ + 'sample_id', + 'vqa_box_id', + 'sample_group', + 'protocol_id', + 'technology_platform', + 'assay_readout', + 'assay_readout_unit', + 'assay_readout_description' +] + +@samples_report.samples.each do |sample| + csv << [ + sample.id, + sample.box.uuid, + "#{sample.box.purpose}-panel", + nil, + nil, + sample.measured_signal, + nil, + nil + ] +end \ No newline at end of file diff --git a/app/views/samples_reports/nih_samples.csv.csvbuilder b/app/views/samples_reports/nih_samples.csv.csvbuilder new file mode 100644 index 000000000..ed0f40d6c --- /dev/null +++ b/app/views/samples_reports/nih_samples.csv.csvbuilder @@ -0,0 +1,44 @@ +csv << [ + 'sample_id', + 'vqa_box_id', + 'sample_group', + 'sample_media', + 'sample_media_id', + 'sample_media_source', + 'sample_media_source_url', + 'sample_concentration', + 'sample_concentration_unit', + 'sample_concentration_reference_gene', + 'virus_sample_id', + 'virus_batch_number', + 'target_analyte_type', + 'target_organism_name', + 'target_organism_taxonomy_id', + 'pango_lineage', + 'who_label', + 'virus_sample_inactivation_method' +] + +@samples_report.samples.each do |sample| + batch = Batch.find_by(batch_number: sample.batch_number) + csv << [ + sample.id, + sample.box.uuid, + "#{sample.box.purpose}-panel", + nil, + nil, + nil, + nil, + sample.concentration, + 'copies/ml', + batch.reference_gene, + sample.id, + sample.batch_number, + 'inactivated virus', + 'SARS-CoV-2', + batch.target_organism_taxonomy_id, + batch.pango_lineage, + batch.who_label, + sample.inactivation_method + ] +end \ No newline at end of file diff --git a/spec/controllers/nih_tables_controller_spec.rb b/spec/controllers/nih_tables_controller_spec.rb index 8c3b4fe0a..e090aa0e3 100644 --- a/spec/controllers/nih_tables_controller_spec.rb +++ b/spec/controllers/nih_tables_controller_spec.rb @@ -26,7 +26,6 @@ it "should download a zip file on show" do get :show, params: { id: @samples_report.id } - #expect sent file to be a zip file expect(response.headers["Content-Type"]).to eq("application/zip") expect(response.headers["Content-Disposition"]).to eq("attachment; filename=\"Test_nih_tables.zip\"") end @@ -34,10 +33,36 @@ it "should contain the Instructions.txt file" do get :show, params: { id: @samples_report.id } - #expect the zip file to contain the Instructions.txt file expect(Zip::File.open_buffer(response.body).entries.map(&:name)).to include("Instructions.txt") end + it "should contain the samples & results table" do + get :show, params: { id: @samples_report.id } + + expect(Zip::File.open_buffer(response.body).entries.map(&:name)).to include("#{@samples_report.name}_samples.csv") + expect(Zip::File.open_buffer(response.body).entries.map(&:name)).to include("#{@samples_report.name}_results.csv") + end + + it "should contain the samples table with the correct data" do + get :show, params: { id: @samples_report.id } + + samples_table = CSV.parse(Zip::File.open_buffer(response.body).entries.find{|e| e.name == "Test_samples.csv"}.get_input_stream.read, headers: true) + + expect(samples_table.count).to eq(@samples_report.samples_report_samples.count) + + expect(samples_table["sample_id"]).to eq(@samples_report.samples_report_samples.map{|srs| srs.sample.id.to_s}) + end + + it "should contain the results table with the correct data" do + get :show, params: { id: @samples_report.id } + + samples_table = CSV.parse(Zip::File.open_buffer(response.body).entries.find{|e| e.name == "Test_results.csv"}.get_input_stream.read, headers: true) + + expect(samples_table.count).to eq(@samples_report.samples_report_samples.count) + + expect(samples_table["sample_id"]).to eq(@samples_report.samples_report_samples.map{|srs| srs.sample.id.to_s}) + end + it "should not allow access to user without read access" do sign_in @other_user get :show, params: { id: @samples_report.id, context: @other_institution.uuid }