From 53da85660cc761fd49b33097ced875e09d3e9eed Mon Sep 17 00:00:00 2001 From: gebele Date: Fri, 23 Mar 2018 07:27:40 +0000 Subject: store uploaded datasets --- application.rb | 79 ++++++++++++++++++++++++++++++++++---------------- helper.rb | 7 +++++ views/predict.haml | 84 +++++++++++++++++++++++++++++++++++++++--------------- views/style.scss | 9 ++++++ 4 files changed, 132 insertions(+), 47 deletions(-) diff --git a/application.rb b/application.rb index 04b5aa3..8f78845 100644 --- a/application.rb +++ b/application.rb @@ -33,6 +33,7 @@ get '/predict/?' do rescue nil end + @existing_datasets = dataset_storage @models = Model::Validation.all @models = @models.delete_if{|m| m.model.name =~ /\b(Net cell association)\b/} @endpoints = @models.collect{|m| m.endpoint}.sort.uniq @@ -136,6 +137,22 @@ get '/predict/dataset/:name' do csv end +get '/download/dataset/:id' do + response['Content-Type'] = "text/csv" + dataset = Dataset.find params[:id] + tempfile = Tempfile.new + tempfile.write(File.read("tmp/"+dataset.name+".csv")) + tempfile.rewind + send_file tempfile, :filename => dataset.name+".csv", :type => "text/csv", :disposition => "attachment" +end + +get '/delete/dataset/:id' do + dataset = Dataset.find params[:id] + dataset.delete + File.delete File.join("tmp/"+dataset.name+".csv") + redirect to("/") +end + get '/predict/csv/:task/:model/:filename/?' do response['Content-Type'] = "text/csv" task = Task.find params[:task].to_s @@ -156,35 +173,49 @@ get '/predict/csv/:task/:model/:filename/?' do end post '/predict/?' do - # process batch prediction - if !params[:fileselect].blank? - if params[:fileselect][:filename] !~ /\.csv$/ - bad_request_error "Wrong file extension for '#{params[:fileselect][:filename]}'. Please upload a CSV file." + if !params[:fileselect].blank? || !params[:existing].blank? + if !params[:existing].blank? + @dataset = Dataset.find params[:existing].keys[0] + @compounds = @dataset.compounds + @filename = @dataset.name end - File.open('tmp/' + params[:fileselect][:filename], "w") do |f| - f.write(params[:fileselect][:tempfile].read) - end - @filename = params[:fileselect][:filename] - begin - input = Dataset.from_csv_file File.join("tmp", params[:fileselect][:filename]), true - $logger.debug "save dataset #{params[:fileselect][:filename]}" - if input.class == OpenTox::Dataset - @dataset = Dataset.find input - @compounds = @dataset.compounds - else + if !params[:fileselect].blank? + if params[:fileselect][:filename] !~ /\.csv$/ + bad_request_error "Wrong file extension for '#{params[:fileselect][:filename]}'. Please upload a CSV file." + end + @filename = params[:fileselect][:filename] + begin + @dataset = Dataset.find_by(:name => params[:fileselect][:filename].sub(/\.csv$/,"")) + if @dataset + $logger.debug "Take file from database." + @compounds = @dataset.compounds + else + File.open('tmp/' + params[:fileselect][:filename], "w") do |f| + f.write(params[:fileselect][:tempfile].read) + end + input = Dataset.from_csv_file File.join("tmp", params[:fileselect][:filename]), true + $logger.debug "Processing '#{params[:fileselect][:filename]}'" + if input.class == OpenTox::Dataset + @dataset = input + @compounds = input.compounds + else + File.delete File.join("tmp", params[:fileselect][:filename]) + bad_request_error "Could not serialize file '#{@filename}'." + end + end + rescue + File.delete File.join("tmp", params[:fileselect][:filename]) bad_request_error "Could not serialize file '#{@filename}'." end - rescue - bad_request_error "Could not serialize file '#{@filename}'." - end - if @compounds.size == 0 - message = dataset[:warnings] - @dataset.delete - bad_request_error message + if @compounds.size == 0 + message = dataset[:warnings] + @dataset.delete + bad_request_error message + end end - + @models = params[:selection].keys # for single predictions in batch @tasks = [] @@ -322,7 +353,7 @@ post '/predict/?' do @pid = task.pid #@dataset.delete - File.delete File.join("tmp", params[:fileselect][:filename]) + #File.delete File.join("tmp", params[:fileselect][:filename]) return haml :batch end diff --git a/helper.rb b/helper.rb index fd3b9f4..dc4b695 100644 --- a/helper.rb +++ b/helper.rb @@ -122,4 +122,11 @@ helpers do csv end + def dataset_storage + all = Dataset.where(:source => /^tmp/) + out = Hash.new + all.reverse.each{|d| out[d.id] = [d.name, d.created_at]} + out + end + end diff --git a/views/predict.haml b/views/predict.haml index 6b1c462..054bfa2 100644 --- a/views/predict.haml +++ b/views/predict.haml @@ -26,7 +26,14 @@ function getInput(){ identifier = document.getElementById("identifier").value.trim(); fileselect = document.getElementById("fileselect").value; - if (fileselect != ""){ + allexisting = document.querySelectorAll('[id^="existing"]'); + existingcsv = false + for (var index = 0; index < allexisting.length; index++) { + if(allexisting[index].checked == true) { + existingcsv = true; + }; + }; + if (fileselect != "" || existingcsv == true){ return 1; }; if (identifier != ""){ @@ -70,6 +77,12 @@ //TODO check file type is csv return true; }; + allexisting = document.querySelectorAll('[id^="existing"]'); + for (var index = 0; index < allexisting.length; index++) { + if(allexisting[index].checked == true) { + return true; + }; + }; alert("Please select a file (csv)."); return false; }; @@ -85,11 +98,12 @@ }; function checkboxes () { var checked = false; - $('input[type="checkbox"]').each(function() { - if ($(this).is(":checked")) { + models = document.querySelectorAll('[id^="selection"]'); + for (var index = 0; index < models.length; index++) { + if(models[index].checked == true) { checked = true; }; - }); + }; if (checked == false){ alert("Please select an endpoint."); $("img.circle").hide(); @@ -114,23 +128,43 @@ %form{:name => "form", :action => to('/predict'), :method => "post", :enctype => "multipart/form-data", :onsubmit => "return !!(showcircle())" } %fieldset#top.well %h2 1. Draw a chemical structure - #insert - %label   - #appletContainer - %br - %label{:for => 'identifier'} - or enter the - %a{:href => "http://en.wikipedia.org/wiki/Simplified_molecular_input_line_entry_specification", :rel => "external"} SMILES - string: - %br - %input{:type => 'text', :name => 'identifier', :id => 'identifier', :size => '60'} - %p - %label{:for=>"fileselect"} - or upload a CSV file for batch predictions - %a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"File format", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"auto", html:"true", content:"One column with compounds and keyword SMILES or InChI in the first row."}} - %br - %span.btn.btn-default.btn-file - %input{:type=>"file", :name=> "fileselect", :id=>"fileselect", :autocomplete=>"off", :accept=>"text/csv"} + %div.row + %div.col-md-6 + #insert + %label   + #appletContainer + %br + %label{:for => 'identifier'} + or enter the + %a{:href => "http://en.wikipedia.org/wiki/Simplified_molecular_input_line_entry_specification", :rel => "external"} SMILES + string: + %br + %input{:type => 'text', :name => 'identifier', :id => 'identifier', :size => '60'} + %p + %label{:for=>"fileselect"} + or upload a CSV file for batch predictions + %a.btn.glyphicon.glyphicon-info-sign{:href=>"javascript:void(0)", :title=>"File format", :tabindex=>"0", data: {trigger:"focus", toggle:"popover", placement:"auto", html:"true", content:"First column must contain a header with \"SMILES\" or \"InChI\" and the compounds. Also note that a file with the same name of a file that already exists won't be processed."}} + %br + %span.btn.btn-default.btn-file + %input{:type=>"file", :name=> "fileselect", :id=>"fileselect", :autocomplete=>"off", :accept=>"text/csv"} + %div.col-md-6 + - if !@existing_datasets.blank? + %label{:for=>"storage"} or select an uploaded CSV file + #storage.storage-list + - @existing_datasets.each do |id,values| + %div.p2 + %input.checkDataset{:type => "checkbox", :name => "existing[#{id}]", :id => "existing[#{id}]", :value => true, :disabled => false} + %div.btn-group{:role=>"group", :aria=>{:label=>"remove-download"}} + %a.btn.btn-secondary{:role=>"button", :href=>to("/delete/dataset/#{id}")} + %i.glyphicon.glyphicon-trash + %a.btn.btn-secondary{:role=>"button", :href=>to("/download/dataset/#{id}")} + %i.glyphicon.glyphicon-save + %div.p2 + %label{:for => "existing[#{id}]"} + = values[0] + %div.p2 + = values[1].strftime("%Y-%m-%d %H:%M:%S") + %hr %fieldset#middle.well %h2 2. Select one or more endpoints @@ -146,6 +180,9 @@ $(".check").prop('checked', false); }; }); + $(".checkDataset").click(function () { + $('.checkDataset').not(this).prop('checked', false); + }); - @endpoints.each do |endpoint| %div{:id=>endpoint.gsub(/\s+/, "_")} %h4.head-back=endpoint @@ -197,6 +234,7 @@ %div.col-md-2 %h2 3. Predict - %div.col-md-10 - %input.btn.btn-warning.h2{ :type => "submit", :id => "submit", :value=>">>", :onclick => "getsmiles()"} + %div.col-md-10.input-group + %button.has-feedback.btn.btn-warning.h2{ :type => "submit", :id => "submit", :value=>"", :onclick => "getsmiles()"} + %span.glyphicon.glyphicon-play %img.h2{:src=>"/images/wait30trans.gif", :id=>"circle", :class=>"circle", :alt=>"wait", :style=>"display:none;"} diff --git a/views/style.scss b/views/style.scss index 46c57c6..fc6f8f2 100644 --- a/views/style.scss +++ b/views/style.scss @@ -26,6 +26,10 @@ } body { background-color:#E7E7E7; + + a { + color: inherit; + } } table.table-borderless tbody tr td{ border-top: none; @@ -111,3 +115,8 @@ tr.hide-top > td { .footer{ margin-top:3em; } +.storage-list { + height: 400px; + overflow-y: auto; + overflow-x: auto; +} -- cgit v1.2.3