From 6e1a5e9b634ec6d1b947c27212cf434a412a589e Mon Sep 17 00:00:00 2001 From: Christoph Helma Date: Wed, 23 Feb 2011 18:06:14 +0100 Subject: application.rb and .gitignore fixed --- .gitignore | 5 +- application.rb | 337 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 324 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index e3debba..f52f036 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ +api_key.rb +*.sqlite3 tmp/* log/* -public/*.owl -*.*~ +public/* diff --git a/application.rb b/application.rb index 15088d5..de11313 100644 --- a/application.rb +++ b/application.rb @@ -1,27 +1,332 @@ require 'rubygems' -# AM LAST: can include both libs, no problems -require File.join(File.expand_path(File.dirname(__FILE__)), 'libfminer/libbbrc/bbrc') # has to be included before openbabel, otherwise we have strange SWIG overloading problems -require File.join(File.expand_path(File.dirname(__FILE__)), 'libfminer/liblast/last') # has to be included before openbabel, otherwise we have strange SWIG overloading problems -require File.join(File.expand_path(File.dirname(__FILE__)), 'last-utils/lu.rb') # AM LAST gem "opentox-ruby", "~> 0" require 'opentox-ruby' -#require 'smarts.rb' -#require 'similarity.rb' -require 'openbabel.rb' -require 'fminer.rb' -require 'lazar.rb' - set :lock, true +helpers do + def next_id + id = Dir["./public/*yaml"].collect{|f| File.basename(f.sub(/.yaml/,'')).to_i}.sort.last + id = 0 if id.nil? + id + 1 + end + + def uri(id) + url_for "/#{id}", :full + end + + # subjectid ist stored as memeber variable, not in params + def load_dataset(id, params,content_type,input_data) + + @uri = uri id + raise "store subject-id in dataset-object, not in params" if params.has_key?(:subjectid) and @subjectid==nil + + content_type = "application/rdf+xml" if content_type.nil? + dataset = OpenTox::Dataset.new(nil, @subjectid) + + case content_type + + when /yaml/ + dataset.load_yaml(input_data) + + when /application\/rdf\+xml/ + dataset.load_rdfxml(input_data) + + when /multipart\/form-data/ , "application/x-www-form-urlencoded" # file uploads + + case params[:file][:type] + + when /yaml/ + dataset.load_yaml(params[:file][:tempfile].read) + + when "application/rdf+xml" + dataset.load_rdfxml_file(params[:file][:tempfile]) + + when "text/csv" + dataset = OpenTox::Dataset.new @uri + dataset.load_csv(params[:file][:tempfile].read) + dataset.add_metadata({ + DC.title => File.basename(params[:file][:filename],".csv"), + OT.hasSource => File.basename(params[:file][:filename]) + }) + + when /ms-excel/ + extension = File.extname(params[:file][:filename]) + case extension + when ".xls" + xls = params[:file][:tempfile].path + ".xls" + File.rename params[:file][:tempfile].path, xls # roo needs these endings + book = Excel.new xls + when ".xlsx" + xlsx = params[:file][:tempfile].path + ".xlsx" + File.rename params[:file][:tempfile].path, xlsx # roo needs these endings + book = Excel.new xlsx + else + raise "#{params[:file][:filename]} is not a valid Excel input file." + end + dataset.load_spreadsheet(book) + dataset.add_metadata({ + DC.title => File.basename(params[:file][:filename],extension), + OT.hasSource => File.basename(params[:file][:filename]) + }) + + else + raise "MIME type \"#{params[:file][:type]}\" not supported." + end + + else + raise "MIME type \"#{content_type}\" not supported." + end + + dataset.uri = @uri # update uri (also in metdata) + dataset.features.keys.each { |f| dataset.features[f][OT.hasSource] = dataset.metadata[OT.hasSource] unless dataset.features[f][OT.hasSource]} + File.open("public/#{@id}.yaml","w+"){|f| f.puts dataset.to_yaml} + end +end + before do - LOGGER.debug "Request: " + request.path + @accept = request.env['HTTP_ACCEPT'] + @accept = 'application/rdf+xml' if @accept == '*/*' or @accept == '' or @accept.nil? + @id = request.path_info.match(/^\/\d+/) + unless @id.nil? + @id = @id.to_s.sub(/\//,'').to_i + + @uri = uri @id + @yaml_file = "public/#{@id}.yaml" + halt 404, "Dataset #{@id} not found." unless File.exists? @yaml_file + + extension = File.extname(request.path_info) + #extension = File.extname(params[:id]).sub(/\./,'') + unless extension.empty? + #request.path_info.sub!(/\.#{extension}$/,'') + case extension + when "html" + @accept = 'text/html' + when "yaml" + @accept = 'application/x-yaml' + when "csv" + @accept = 'text/csv' + when "rdfxml" + @accept = 'application/rdf+xml' + when "xls" + @accept = 'application/ms-excel' + else + halt 404, "File format #{extension} not supported." + end + end + end + + # make sure subjectid is not included in params, subjectid is set as member variable + params.delete(:subjectid) end -# Get a list of available algorithms -# -# @return [text/uri-list] algorithm URIs +## REST API + +# Get a list of available datasets +# @return [text/uri-list] List of available datasets get '/?' do - response['Content-Type'] = 'text/uri-list' - [ url_for('/lazar', :full), url_for('/fminer/bbrc', :full), url_for('/fminer/last', :full) ].join("\n") + "\n" + response['Content-Type'] = 'text/uri-list' + Dir["./public/*yaml"].collect{|f| File.basename(f.sub(/.yaml/,'')).to_i}.sort.collect{|n| uri n}.join("\n") + "\n" +end + +# Get a dataset representation +# @param [Header] Accept one of `application/rdf+xml, application-x-yaml, text/csv, application/ms-excel` (default application/rdf+xml) +# @return [application/rdf+xml, application-x-yaml, text/csv, application/ms-excel] Dataset representation +get '/:id' do + + case @accept + + when /rdf/ # redland sends text/rdf instead of application/rdf+xml + file = "public/#{params[:id]}.rdfxml" + unless File.exists? file # lazy rdfxml generation + dataset = YAML.load_file(@yaml_file) + File.open(file,"w+") { |f| f.puts dataset.to_rdfxml } + end + response['Content-Type'] = 'application/rdf+xml' + File.read(file) + + when /yaml/ + response['Content-Type'] = 'application/x-yaml' + File.read(@yaml_file) + + when /html/ + response['Content-Type'] = 'text/html' + OpenTox.text_to_html File.read(@yaml_file) + + when "text/csv" + response['Content-Type'] = 'text/csv' + YAML.load_file(@yaml_file).to_csv + + when /ms-excel/ + file = "public/#{params[:id]}.xls" + YAML.load_file(@yaml_file).to_xls.write(file) unless File.exists? file # lazy xls generation + response['Content-Type'] = 'application/ms-excel' + File.open(file).read + + else + halt 404, "Content-type #{@accept} not supported." + end +end + +# Get metadata of the dataset +# @return [application/rdf+xml] Metadata OWL-DL +get '/:id/metadata' do + + metadata = YAML.load_file(@yaml_file).metadata + + case @accept + when /rdf/ # redland sends text/rdf instead of application/rdf+xml + response['Content-Type'] = 'application/rdf+xml' + serializer = OpenTox::Serializer::Owl.new + serializer.add_metadata url_for("/#{params[:id]}",:full), metadata + serializer.to_rdfxml + when /yaml/ + response['Content-Type'] = 'application/x-yaml' + metadata.to_yaml + end + +end + +# Get a dataset feature +# @param [Header] Accept one of `application/rdf+xml or application-x-yaml` (default application/rdf+xml) +# @return [application/rdf+xml,application/x-yaml] Feature metadata +get %r{/(\d+)/feature/(.*)$} do |id,feature| + + @id = id + @uri = uri @id + @yaml_file = "public/#{@id}.yaml" + feature_uri = url_for("/#{@id}/feature/#{URI.encode(feature)}",:full) # work around racks internal uri decoding + metadata = YAML.load_file(@yaml_file).features[feature_uri] + + case @accept + when /rdf/ # redland sends text/rdf instead of application/rdf+xml + response['Content-Type'] = 'application/rdf+xml' + serializer = OpenTox::Serializer::Owl.new + serializer.add_feature feature_uri, metadata + serializer.to_rdfxml + when /yaml/ + response['Content-Type'] = 'application/x-yaml' + metadata.to_yaml + end + +end + +# Get a list of all features +# @param [Header] Accept one of `application/rdf+xml, application-x-yaml, text/uri-list` (default application/rdf+xml) +# @return [application/rdf+xml, application-x-yaml, text/uri-list] Feature list +get '/:id/features' do + + features = YAML.load_file(@yaml_file).features + + case @accept + when /rdf/ # redland sends text/rdf instead of application/rdf+xml + response['Content-Type'] = 'application/rdf+xml' + serializer = OpenTox::Serializer::Owl.new + features.each { |feature,metadata| serializer.add_feature feature, metadata } + serializer.to_rdfxml + when /yaml/ + response['Content-Type'] = 'application/x-yaml' + features.to_yaml + when "text/uri-list" + response['Content-Type'] = 'text/uri-list' + features.keys.join("\n") + "\n" + end +end + +# Get a list of all compounds +# @return [text/uri-list] Feature list +get '/:id/compounds' do + response['Content-Type'] = 'text/uri-list' + YAML.load_file(@yaml_file).compounds.join("\n") + "\n" +end + +# Create a new dataset. +# +# Posting without parameters creates and saves an empty dataset (with assigned URI). +# Posting with parameters creates and saves a new dataset. +# Data can be submitted either +# - in the message body with the appropriate Content-type header or +# - as file uploads with Content-type:multipart/form-data and a specified file type +# @example +# curl -X POST -F "file=@training.csv;type=text/csv" http://webservices.in-silico.ch/dataset +# @param [Header] Content-type one of `application/x-yaml, application/rdf+xml, multipart/form-data/` +# @param [BODY] - string with data in selected Content-type +# @param [optional] file, for file uploads, Content-type should be multipart/form-data, please specify the file type `application/rdf+xml, application-x-yaml, text/csv, application/ms-excel` +# @return [text/uri-list] Task URI or Dataset URI (empty datasets) +post '/?' do + + response['Content-Type'] = 'text/uri-list' + + # it could be that the read function works only once!, store in varible + input_data = request.env["rack.input"].read + @id = next_id + @uri = uri @id + @yaml_file = "public/#{@id}.yaml" + if params.size == 0 and input_data.size==0 + File.open(@yaml_file,"w+"){|f| f.puts OpenTox::Dataset.new(@uri).to_yaml} + OpenTox::Authorization.check_policy(@uri, @subjectid) if File.exists? @yaml_file + @uri + else + task = OpenTox::Task.create("Converting and saving dataset ", @uri) do + load_dataset @id, params, request.content_type, input_data + OpenTox::Authorization.check_policy(@uri, @subjectid) if File.exists? @yaml_file + @uri + end + halt 503,task.uri+"\n" if task.status == "Cancelled" + halt 202,task.uri+"\n" + end +end + +# Save a dataset, will overwrite all existing data +# +# Data can be submitted either +# - in the message body with the appropriate Content-type header or +# - as file uploads with Content-type:multipart/form-data and a specified file type +# @example +# curl -X POST -F "file=@training.csv;type=text/csv" http://webservices.in-silico.ch/dataset/1 +# @param [Header] Content-type one of `application/x-yaml, application/rdf+xml, multipart/form-data/` +# @param [BODY] - string with data in selected Content-type +# @param [optional] file, for file uploads, Content-type should be multipart/form-data, please specify the file type `application/rdf+xml, application-x-yaml, text/csv, application/ms-excel` +# @return [text/uri-list] Task ID +post '/:id' do + LOGGER.debug @uri + response['Content-Type'] = 'text/uri-list' + task = OpenTox::Task.create("Converting and saving dataset ", @uri) do + FileUtils.rm Dir["public/#{@id}.*"] + load_dataset @id, params, request.content_type, request.env["rack.input"].read + @uri + end + halt 503,task.uri+"\n" if task.status == "Cancelled" + halt 202,task.uri.to_s+"\n" +end + +# Delete a dataset +# @return [text/plain] Status message +delete '/:id' do + LOGGER.debug "deleting dataset with id "+@id.to_s + begin + FileUtils.rm Dir["public/#{@id}.*"] + if @subjectid and !File.exists? @yaml_file and @uri + begin + res = OpenTox::Authorization.delete_policies_from_uri(@uri, @subjectid) + LOGGER.debug "Policy deleted for Dataset URI: #{@uri} with result: #{res}" + rescue + LOGGER.warn "Policy delete error for Dataset URI: #{@uri}" + end + end + response['Content-Type'] = 'text/plain' + "Dataset #{@id} deleted." + rescue + halt 404, "Dataset #{@id} does not exist." + end +end + +# Delete all datasets +# @return [text/plain] Status message +delete '/?' do + FileUtils.rm Dir["public/*.rdfxml"] + FileUtils.rm Dir["public/*.xls"] + FileUtils.rm Dir["public/*.yaml"] + response['Content-Type'] = 'text/plain' + "All datasets deleted." end -- cgit v1.2.3