diff options
author | Christoph Helma <helma@in-silico.ch> | 2012-05-09 16:19:35 +0000 |
---|---|---|
committer | Christoph Helma <helma@in-silico.ch> | 2012-05-09 16:19:35 +0000 |
commit | c7822fc4c461ab6d10649a5964ecb10f7f4c54d7 (patch) | |
tree | 61e030c4c6478af4a90e96d1b2fb292453928c56 | |
parent | 5d36335505385608179f9f50811dff0e605f307f (diff) | |
parent | 577766d62353ea9c57b0459417aea25703882021 (diff) |
Merge branch 'feature/task' into development
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | lib/4store.rb | 76 | ||||
-rw-r--r-- | lib/authorization-helper.rb | 5 | ||||
-rw-r--r-- | lib/opentox.rb | 44 | ||||
-rw-r--r-- | opentox-server.gemspec | 3 |
6 files changed, 76 insertions, 56 deletions
@@ -1,5 +1,5 @@ +Gemfile.lock *.gem .bundle pkg/* -Gemfile.lock *~ @@ -1 +1 @@ -0.0.3 +1.0.0 diff --git a/lib/4store.rb b/lib/4store.rb index b20af00..f2e3fcd 100644 --- a/lib/4store.rb +++ b/lib/4store.rb @@ -2,8 +2,6 @@ module OpenTox module Backend class FourStore - #TODO: catch 4store errors - @@mime_format = { "application/rdf+xml" => :rdfxml, "text/turtle" => :turtle, @@ -14,8 +12,8 @@ module OpenTox #"text/x-yaml" => :yaml, #"text/yaml" => :yaml, "text/html" => :html, - # TODO: compression, forms #/sparql/ => :sparql #removed to prevent sparql injections + 'application/sparql-results+xml' => :sparql } @@format_mime = { @@ -26,19 +24,19 @@ module OpenTox #:json => "application/json", #:yaml => "text/yaml", :html => "text/html", + :sparql => 'application/sparql-results+xml' } - @@accept_formats = [:rdfxml, :turtle, :ntriples, :uri_list, :html] #, :json, :yaml] + @@accept_formats = [:rdfxml, :turtle, :ntriples, :uri_list, :html, :sparql] #, :json, :yaml] @@content_type_formats = [:rdfxml, :turtle, :ntriples]#, :json, :yaml] - @@rdf_formats = [:rdfxml, :turtle, :ntriples] def self.list mime_type mime_type = "text/html" if mime_type.match(%r{\*/\*}) bad_request_error "'#{mime_type}' is not a supported mime type. Please specify one of #{@@accept_formats.collect{|f| @@format_mime[f]}.join(", ")} in the Accept Header." unless @@accept_formats.include? @@mime_format[mime_type] if mime_type =~ /json|yaml|uri-list/ - sparql = "SELECT ?s WHERE {?s <#{RDF.type}> <#{@@class}>. }" + sparql = "SELECT DISTINCT ?g WHERE {GRAPH ?g {?s ?p ?o} }" elsif mime_type =~ /turtle|html|rdf|plain/ - sparql = "CONSTRUCT {?s ?p ?o.} WHERE {?s <#{RDF.type}> <#{@@class}>; ?p ?o. }" + sparql = "CONSTRUCT {?s ?p ?o.} WHERE {?s <#{RDF.type}> <#{klass}>; ?p ?o. }" end query sparql, mime_type end @@ -46,19 +44,22 @@ module OpenTox def self.get uri, mime_type mime_type = "text/html" if mime_type.match(%r{\*/\*}) bad_request_error "'#{mime_type}' is not a supported mime type. Please specify one of #{@@accept_formats.collect{|f| @@format_mime[f]}.join(", ")} in the Accept Header." unless @@accept_formats.include? @@mime_format[mime_type] - not_found_error "#{uri} not found." unless list("text/uri-list").split("\n").include?(uri) + not_found_error "#{uri} not found." unless available? uri sparql = "CONSTRUCT {?s ?p ?o.} FROM <#{uri}> WHERE { ?s ?p ?o. }" query sparql, mime_type end def self.post uri, rdf, mime_type - bad_request_error "'#{mime_type}' is not a supported content type. Please use one of #{@@content_type_formats.collect{|f| @@format_mime[f]}.join(", ")}." unless @@content_type_formats.include? @@mime_format[mime_type] - rdf = convert rdf, @@mime_format[mime_type], :ntriples#, uri unless mime_type == 'text/plain' + bad_request_error "'#{mime_type}' is not a supported content type. Please use one of #{@@content_type_formats.collect{|f| @@format_mime[f]}.join(", ")}." unless @@content_type_formats.include? @@mime_format[mime_type] or mime_type == "multipart/form-data" + rdf = convert rdf, @@mime_format[mime_type], :ntriples + rdf = "<#{uri}> <#{RDF.type}> <#{klass}>." unless rdf # create empty resource + rdf += "\n<#{uri}> <#{RDF::DC.date}> \"#{DateTime.now}\"." unless rdf.match(%r{#{RDF::DC.date}}) RestClient.post File.join(four_store_uri,"data")+"/", :data => rdf, :graph => uri, "mime-type" => "application/x-turtle" # not very consistent in 4store end def self.put uri, rdf, mime_type, skip_rewrite=false bad_request_error "'#{mime_type}' is not a supported content type. Please use one of #{@@content_type_formats.collect{|f| @@format_mime[f]}.join(", ")}." unless @@content_type_formats.include? @@mime_format[mime_type] + bad_request_error "Reqest body empty." unless rdf # create empty resource uuid = uri.sub(/\/$/,'').split('/').last bad_request_error "'#{uri}' is not a valid URI." unless uuid =~ /[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/ if !skip_rewrite @@ -66,19 +67,23 @@ module OpenTox elsif mime_type != "text/plain" # ntriples are not converted rdf = convert rdf, @@mime_format[mime_type], :ntriples end - rdf = "<#{uri}> <#{RDF.type}> <#{@@class}>." unless rdf # create empty resource RestClient.put File.join(four_store_uri,"data",uri), rdf, :content_type => "application/x-turtle" # content-type not very consistent in 4store end def self.delete uri - RestClientWrapper.delete data_uri uri + RestClientWrapper.delete data_uri(uri) + end + + def self.update sparql + RestClient.post(update_uri, :update => sparql ) end def self.query sparql, mime_type if sparql =~ /SELECT/i - xml = RestClient.post File.join(four_store_uri,"sparql")+"/", :query => sparql - #TODO request tab delimited format to speed up parsing - list = parse_sparql_xml_results(xml).collect{|hash| hash["s"]} + return RestClient.get(sparql_uri, :params => { :query => sparql }, :accept => mime_type).body.gsub(/<|>/,'').split("\n") if mime_type == 'application/sparql-results+xml' + list = RestClient.get(sparql_uri, :params => { :query => sparql }, :accept => "text/plain").body.gsub(/<|>/,'').split("\n") + list.shift + return list unless mime_type case mime_type when /json/ return list.to_json @@ -98,7 +103,7 @@ module OpenTox when /html/ # TODO: fix and improve html = "<html><body>" - html += convert(nt,:ntriples, :turtle).gsub(%r{<(.*)>},'<<a href="\1">\1</a>>').gsub(/\n/,'<br/>')#.gsub(/ /,' ') + html += convert(nt,:ntriples, :turtle).gsub(%r{<(.*)>},'<<a href="\1">\1</a>>').gsub(/\n/,'<br/>') html += "</body></html>" return html when "application/rdf+xml" @@ -112,6 +117,17 @@ module OpenTox private + def self.klass + RDF::OT[SERVICE.capitalize] + end + + def self.available? uri + #sparql = "SELECT DISTINCT ?s WHERE {GRAPH <#{uri}> {?s ?p ?o} }" + sparql = "SELECT DISTINCT ?s WHERE {GRAPH <#{uri}> {?s <#{RDF.type}> <#{klass}>} }" + r = query(sparql, nil) + r.size == 1 and r.first == uri + end + def self.convert rdf_string, input_format, output_format, rewrite_uri=nil rewrite_uri ? serialize(parse_and_rewrite_uri(rdf_string,input_format, rewrite_uri), output_format) : serialize(parse(rdf_string,input_format), output_format) end @@ -122,7 +138,7 @@ module OpenTox statements = [] # use array instead of graph for performance reasons RDF::Reader.for(format).new(string) do |reader| reader.each_statement do |statement| - subject = statement.subject if statement.predicate == RDF.type and statement.object == @@class + subject = statement.subject if statement.predicate == RDF.type and statement.object == klass statements << statement end end @@ -144,8 +160,9 @@ module OpenTox def self.serialize rdf, format if format == :turtle # prefixes seen to need RDF::N3 - # TODO add prefixes - string = RDF::N3::Writer.for(format).buffer(:prefixes => {:ot => "http://www.opentox.org/api/1.2#"}) do |writer| + prefixes = {:rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"} + ['OT', 'DC', 'XSD'].each{|p| prefixes[p.downcase.to_sym] = eval("RDF::#{p}.to_s") } + string = RDF::N3::Writer.for(format).buffer(:prefixes => prefixes) do |writer| rdf.each{|statement| writer << statement} end else @@ -157,6 +174,7 @@ module OpenTox end def self.four_store_uri + # TODO remove credentials from URI 9security risk in tasks) $four_store[:uri].sub(%r{//},"//#{$four_store[:user]}:#{$four_store[:password]}@") end @@ -164,24 +182,12 @@ module OpenTox File.join(four_store_uri, "sparql") + '/' end - def self.data_uri uri - File.join(four_store_uri, "data","?graph=#{uri}") + def self.update_uri + File.join(four_store_uri, "update") + '/' end - def self.parse_sparql_xml_results(xml) - results = [] - doc = REXML::Document.new(REXML::Source.new(xml)) - doc.elements.each("*/results/result") do |result| - result_hash = {} - result.elements.each do |binding| - key = binding.attributes["name"] - value = binding.elements[1].text - type = binding.elements[1].name - result_hash[key] = value - end - results.push result_hash - end - results + def self.data_uri uri + File.join(four_store_uri, "data","?graph=#{uri}") end end diff --git a/lib/authorization-helper.rb b/lib/authorization-helper.rb index 92bc865..11d8ae8 100644 --- a/lib/authorization-helper.rb +++ b/lib/authorization-helper.rb @@ -78,7 +78,8 @@ module OpenTox uri = uri.sub(" ", "%20") #dirty hacks => to fix uri = uri[0,uri.index("InChI=")] if uri.index("InChI=") out = URI.parse(uri) - out.path = out.path[0, out.path.length - (out.path.reverse.rindex(/\/{1}\d+\/{1}/))] if out.path.index(/\/{1}\d+\/{1}/) #cuts after /id/ for a&a + out.path = out.path[0, out.path.length - (out.path.reverse.rindex(/\/{1}\d+\/{1}/))] if out.path.index(/\/{1}\d+\/{1}/) #cuts after numeric /id/ for a&a + out.path.sub! /(\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}).*/, '\1' # cut after uuid out.path = out.path.split('.').first #cut extension port = (out.scheme=="http" && out.port==80)||(out.scheme=="https" && out.port==443) ? "" : ":#{out.port.to_s}" "#{out.scheme}://#{out.host}#{port}#{out.path.chomp("/")}" #" @@ -128,4 +129,4 @@ module OpenTox end end end -end
\ No newline at end of file +end diff --git a/lib/opentox.rb b/lib/opentox.rb index 7a73d66..31a6e82 100644 --- a/lib/opentox.rb +++ b/lib/opentox.rb @@ -1,7 +1,8 @@ require 'sinatra/base' -require "sinatra/reloader" - ENV["RACK_ENV"] ||= "production" +require "sinatra/reloader" if ENV["RACK_ENV"] == "development" +require File.join(ENV["HOME"],".opentox","config","#{SERVICE}.rb") + logfile = File.join(ENV['HOME'], ".opentox","log","#{ENV["RACK_ENV"]}.log") $logger = OTLogger.new(logfile) @@ -23,6 +24,19 @@ module OpenTox before do request.content_type ? response['Content-Type'] = request.content_type : response['Content-Type'] = request.env['HTTP_ACCEPT'] + parse_input if request.request_method =~ /POST|PUT/ + end + + helpers do + def parse_input + if request.content_type == "multipart/form-data" + @body = File.read(params[:file][:tempfile]) + @content_type = params[:file][:type] + else + @body = request.body.read + @content_type = request.content_type + end + end end # Attention: Error within tasks are catched by Task.create @@ -43,38 +57,36 @@ module OpenTox # see http://jcalcote.wordpress.com/2008/10/16/put-or-post-the-rest-of-the-story/ # Get a list of objects at the server - get '/?' do + get "/#{SERVICE}/?" do FourStore.list request.env['HTTP_ACCEPT'] end # Create a new resource - # TODO: handle multipart uploads - post '/?' do - rdf = request.body.read - uri = uri(SecureRandom.uuid) - FourStore.put(uri, rdf, request.content_type) unless rdf == '' + post "/#{SERVICE}/?" do + uri = uri("/#{SERVICE}/#{SecureRandom.uuid}") + FourStore.put(uri, @body, @content_type) response['Content-Type'] = "text/uri-list" uri end # Get resource representation - get '/:id/?' do - FourStore.get(uri("/#{params[:id]}"), request.env['HTTP_ACCEPT']) + get "/#{SERVICE}/:id/?" do + FourStore.get(uri("/#{SERVICE}/#{params[:id]}"), request.env['HTTP_ACCEPT']) end # Modify (i.e. add rdf statments to) a resource - post '/:id/?' do - FourStore.post uri("/#{params[:id]}"), request.body.read, request.content_type + post "/#{SERVICE}/:id/?" do + FourStore.post uri("/#{SERVICE}/#{params[:id]}"), @body, @content_type end # Create or updata a resource - put '/:id/?' do - FourStore.put uri("/#{params[:id]}"), request.body.read, request.content_type + put "/#{SERVICE}/:id/?" do + FourStore.put uri("/#{SERVICE}/#{params[:id]}"), @body, @content_type end # Delete a resource - delete '/:id/?' do - FourStore.delete uri("/#{params[:id]}") + delete "/#{SERVICE}/:id/?" do + FourStore.delete uri("/#{SERVICE}/#{params[:id]}") end end diff --git a/opentox-server.gemspec b/opentox-server.gemspec index 1074fbf..199a67a 100644 --- a/opentox-server.gemspec +++ b/opentox-server.gemspec @@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__) Gem::Specification.new do |s| s.name = "opentox-server" - s.version = "0.0.3" + s.version = File.read("./VERSION") s.authors = ["Christoph Helma, Martin Guetlein, Andreas Maunz, Micha Rautenberg, David Vorgrimmler"] s.email = ["helma@in-silico.ch"] s.homepage = "http://github.com/opentox/opentox-server" @@ -25,6 +25,7 @@ Gem::Specification.new do |s| s.add_runtime_dependency 'sinatra' s.add_runtime_dependency 'sinatra-contrib' s.add_runtime_dependency 'roo' + s.add_runtime_dependency 'spreadsheet', "= 0.6.8" # cannot load 0.7.0 s.add_runtime_dependency 'unicorn' s.add_runtime_dependency 'rdf-n3' end |