require 'rbbt' require 'rbbt/workflow' require 'sinatra/base' require 'json' require 'rbbt/rest/common/locate' require 'rbbt/rest/common/misc' require 'rbbt/rest/common/users' require 'rbbt/rest/entity/locate' require 'rbbt/rest/entity/helpers' require 'rbbt/rest/entity/render' require 'rbbt/rest/entity/list' require 'rbbt/rest/entity/map' require 'rbbt/rest/entity/rest' require 'rbbt/rest/entity/favourites' require 'rbbt/rest/entity/finder' require 'rbbt/rest/entity/entity_card' require 'rbbt/rest/entity/entity_list_card' require 'rbbt/rest/entity/entity_map_card' require 'rbbt/rest/entity/action_card' require 'rbbt/rest/entity/list_container' require 'rbbt/rest/entity/action_controller' require 'rbbt/rest/knowledge_base' require 'rbbt/statistics/rank_product' module Sinatra module RbbtRESTEntity def self.registered(base) base.module_eval do helpers EntityRESTHelpers set :favourites_dir, Rbbt.var.find.sinatra.favourites set :favourite_lists_dir, Rbbt.var.find.sinatra.favourite_lists set :favourite_maps_dir, Rbbt.var.find.sinatra.favourite_maps set :finder, nil get /^\/entity.*/ do @cache_type = :asynchronous if @cache_type.nil? pass end #{{{ Finder get '/find' do halt 200 if params[:term].nil? or params[:term].empty? term = params[:term] sorted_results = finder_find(term) raise "No finder defined" unless settings.respond_to? :finder and not settings.finder.nil? if request.xhr? content_type "application/json" halt 200, sorted_results.to_json else i = sorted_results.first raise "Term not recognized: #{ term }" if i.nil? redirect to(Entity::REST.entity_url(i[:code], i[:format], i[:namespace])) end end post '/find' do term = consume_parameter :term if term =~ /(.*) \[(.*)\]$/ term = $1 namespace, format = $2.split(":") format, namespace = namespace, nil if format.nil? redirect to(Entity::REST.entity_url(term, format, :organism => namespace)) else sorted_results = finder_find(term) i = sorted_results.first halt 404, "Term not recognized: #{ term }" if i.nil? redirect to(Entity::REST.entity_url(i[:code], i[:format], :organism => i[:namespace])) end end #{{{ Entities get '/entity/:entity_type/:entity' do entity_type = consume_parameter :entity_type entity = consume_parameter :entity entity_type = Entity::REST.restore_element(entity_type) entity = setup_entity(entity_type, entity, @clean_params) @entity = entity entity_render(entity) end get '/entity_action/:entity_type/:action/:entity' do entity_type = consume_parameter :entity_type entity = consume_parameter :entity action = consume_parameter :action entity_type = Entity::REST.restore_element(entity_type) entity = setup_entity(entity_type, entity, @clean_params) @entity = entity entity_action_render(entity, action, @clean_params) end #{{{ Entity lists get '/entity_list/:entity_type/new/' do entity_type = consume_parameter :entity_type entity_type = Entity::REST.restore_element(entity_type) mod = Entity.formats[entity_type.split(":").first] list = mod.setup([]) entity_list_action_render(list, 'new', "New #{mod} list", @clean_params.merge(:entity_type => entity_type)) end get '/entity_list/:entity_type/edit/:list_id' do entity_type = consume_parameter :entity_type list_id = consume_parameter :list_id entity_type = Entity::REST.restore_element(entity_type) list_id = Entity::REST.restore_element(list_id) list = Entity::List.load_list(entity_type.split(":").first, list_id, user) entity_list_action_render(list, 'edit', list_id, @clean_params) end get '/entity_list/:entity_type/:list_id' do entity_type = consume_parameter :entity_type list_id = consume_parameter :list_id entity_type = Entity::REST.restore_element(entity_type) list_id = Entity::REST.restore_element(list_id) list = Entity::List.load_list(entity_type.split(":").first, list_id, user) raise "List not found" if list.nil? case @format when :raw, :literal content_type "text/tab-separated-values" user_file = Entity::List.list_file(entity_type.split(":").first, list_id, user) send_file user_file if File.exists? user_file global_file = Entity::List.list_file(entity_type.split(":").first, list_id, nil) send_file global_file if File.exists? global_file raise "List file not found: #{ list_id }" when :json content_type "application/json" halt 200, list_json(list) when :info content_type "application/json" halt 200, list.info.to_json when :list content_type "text/plain" halt 200, list * "\n" when :name name = list.name if name.respond_to? :list_link a = name.list_link :length, list_id.sub(/ \(format:.*?\)|$/, " (format: Name)"), :ensembl => false redirect to(a.match(/href=(["'])(.*?)\1/)[2]) else content_type "text/plain" halt 200, name * "\n" end when :ensembl ensembl = list.ensembl a = ensembl.list_link :length, list_id.sub(/ \(format:.*?\)|$/, " (format: Ensembl)") redirect to(a.match(/href=(["'])(.*?)\1/)[2]) else entity_list_render(list, list_id) end end get '/entity_list_action/:entity_type/:action/:list_id' do entity_type = consume_parameter :entity_type list_id = consume_parameter :list_id action = consume_parameter :action entity_type = Entity::REST.restore_element(entity_type) list_id = Entity::REST.restore_element(list_id) list = Entity::List.load_list(entity_type.split(":").first, list_id, user) entity_list_action_render(list, action, list_id, @clean_params) end post '/entity_list/:entity_type/:list_id' do list_id = consume_parameter :list_id list_id = list_id.gsub("'", '"') entity_type = consume_parameter :entity_type entity_type = Entity::REST.restore_element(entity_type) type, format = entity_type.split(":") entities = consume_parameter :entities entity_file = consume_parameter :entities__param_file entities = fix_input(:array, entities, entity_file) annotations = consume_parameter :annotations annotations = JSON.parse(annotations) annotations[:format] = format if format annotations[:annotation_types] ||= [type] mod = Kernel.const_get(type) list = mod.setup(entities.reject{|e| e.empty?}, annotations) Entity::List.save_list(type, list_id, list, user) redirect to(Entity::REST.entity_list_url(list_id, type)) end #{{{ List Management get '/entity_list/intersect/:entity_type/:list_id' do entity_type = consume_parameter :entity_type list_id = consume_parameter :list_id other_list_id = consume_parameter :other_list_id entity_type = Entity::REST.restore_element(entity_type) type = entity_type.split(":").first list_id = Entity::REST.restore_element(list_id) list = Entity::List.load_list(type, list_id, user) other_list_id = Entity::REST.restore_element(other_list_id) other_list = Entity::List.load_list(type, other_list_id, user) new_list = list.subset(other_list) new_list_id = [list_id, other_list_id] * " ^ " new_list_id = [Misc.digest(list_id), Misc.digest(other_list_id)] * " ^ " if new_list_id.length > 200 Entity::List.save_list(type, new_list_id, new_list, user) redirect to(Entity::REST.entity_list_url(new_list_id, type)) end get '/entity_list/remove/:entity_type/:list_id' do entity_type = consume_parameter :entity_type list_id = consume_parameter :list_id other_list_id = consume_parameter :other_list_id entity_type = Entity::REST.restore_element(entity_type) type = entity_type.split(":").first list_id = Entity::REST.restore_element(list_id) list = Entity::List.load_list(type, list_id, user) other_list_id = Entity::REST.restore_element(other_list_id) other_list = Entity::List.load_list(type, other_list_id, user) new_list = list.remove(other_list) new_list_id = [list_id, other_list_id] * " - " new_list_id = [Misc.digest(list_id), Misc.digest(other_list_id)] * " ~ " if new_list_id.length > 200 Entity::List.save_list(type, new_list_id, new_list, user) redirect to(Entity::REST.entity_list_url(new_list_id, type)) end get '/entity_list/add/:entity_type/:list_id' do entity_type = consume_parameter :entity_type list_id = consume_parameter :list_id other_list_id = consume_parameter :other_list_id entity_type = Entity::REST.restore_element(entity_type) type = entity_type.split(":").first list_id = Entity::REST.restore_element(list_id) list = Entity::List.load_list(type, list_id, user) other_list_id = Entity::REST.restore_element(other_list_id) other_list = Entity::List.load_list(type, other_list_id, user) new_list = list.concat(other_list) new_list_id = [list_id, other_list_id] * " PLUS " new_list_id = [Misc.digest(list_id), Misc.digest(other_list_id)] * " PLUS " if new_list_id.length > 200 Entity::List.save_list(type, new_list_id, new_list, user) redirect to(Entity::REST.entity_list_url(new_list_id, type)) end #{{{ Entity maps get '/entity_map/:entity_type/:column/:map_id' do entity_type = consume_parameter :entity_type map_id = consume_parameter :map_id column = consume_parameter :column entity_type = Entity::REST.restore_element(entity_type) column = Entity::REST.restore_element(column) map_id = Entity::REST.restore_element(map_id) map = Entity::Map.load_map(entity_type.split(":").first, column, map_id, user) case @format when :name file = Entity::Map.map_file(entity_type.split(":").first, column, map_id, user) file = Entity::Map.map_file(entity_type.split(":").first, column, map_id, nil) unless File.exists? file new = TSVWorkflow.job(:change_id, "Map #{ map_id }", :format => "Associated Gene Name", :tsv => TSV.open(file)).exec new_id = map_id << " [Names]" Entity::Map.save_map(entity_type, column, new_id, new, user) redirect to(Entity::REST.entity_map_url(new_id, entity_type, column)) when :ensembl file = Entity::Map.map_file(entity_type.split(":").first, column, map_id, user) file = Entity::Map.map_file(entity_type.split(":").first, column, map_id, nil) unless File.exists? file new = TSVWorkflow.job(:change_id, "Map #{ map_id }", :format => "Ensembl Gene ID", :tsv => TSV.open(file)).exec new_id = map_id << " [Ensembl]" Entity::Map.save_map(entity_type, column, new_id, new, user) redirect to(Entity::REST.entity_map_url(new_id, entity_type, column)) when :pvalue_score file = Entity::Map.map_file(entity_type.split(":").first, column, map_id, user) file = Entity::Map.map_file(entity_type.split(":").first, column, map_id, nil) unless File.exists? file tsv = TSV.open(file) tsv.process tsv.fields.first do |value| value = value.flatten.first if Array === value (1 - value.to_f) / value.to_f end tsv.fields = [tsv.fields.first + " score"] tsv.type = :single tsv.cast = :to_f new_id = map_id << " [Pvalue score]" column = 'Pvalue Score' Entity::Map.save_map(entity_type, column, new_id, tsv, user) redirect to(Entity::REST.entity_map_url(new_id, entity_type, column)) when :ranks file = Entity::Map.map_file(entity_type.split(":").first, column, map_id, user) file = Entity::Map.map_file(entity_type.split(":").first, column, map_id, nil) unless File.exists? file tsv = TSV.open(file) new = tsv.ranks_for(tsv.fields.first) new_id = map_id << " [Ranks]" column = 'Ranks' Entity::Map.save_map(entity_type, column, new_id, new, user) redirect to(Entity::REST.entity_map_url(new_id, entity_type, column)) when :invert_ranks file = Entity::Map.map_file(entity_type.split(":").first, column, map_id, user) file = Entity::Map.map_file(entity_type.split(":").first, column, map_id, nil) unless File.exists? file tsv = TSV.open(file) size = tsv.size tsv.process "Rank" do |v| if Array === v [(size - v.first.to_i).to_s] else (size - v.to_i).to_s end end new_id = map_id.dup column = 'Ranks' Entity::Map.save_map(entity_type, column, new_id, tsv, user) redirect to(Entity::REST.entity_map_url(new_id, entity_type, column)) when :raw, :literal content_type "text/tab-separated-values" user_file = Entity::Map.map_file(entity_type.split(":").first, column, map_id, user) send_file user_file if File.exists? user_file global_file = Entity::Map.map_file(entity_type.split(":").first, column, map_id, nil) send_file global_file if File.exists? global_file raise "Map file not found: #{ map_id }" when :json file = Entity::Map.map_file(entity_type.split(":").first, column, map_id, user) file = Entity::Map.map_file(entity_type.split(":").first, column, map_id, nil) unless File.exists? file content_type "application/json" halt 200, TSV.open(file).to_json else map = Entity::Map.load_map(entity_type.split(":").first, column, map_id, user) entity_map_render(map_id, entity_type.split(":").first, column) end end get '/entity_map_action/:entity_type/:column/:action/:map_id' do action = consume_parameter :action entity_type = Entity::REST.restore_element(consume_parameter :entity_type) column = Entity::REST.restore_element(consume_parameter :column) map_id = Entity::REST.restore_element(consume_parameter :map_id) map = Entity::Map.load_map(entity_type.split(":").first, column, map_id, user) entity_map_action_render(map, action, map_id, @clean_params) end get '/entity_map/rename/:entity_type/:column/:map_id' do new_id = params[:new_name] entity_type = Entity::REST.restore_element(params[:entity_type]) column = Entity::REST.restore_element(params[:column]) map_id = Entity::REST.restore_element(params[:map_id]) map = Entity::Map.load_map(entity_type.split(":").first, column, map_id, user) Entity::Map.save_map(entity_type, column, new_id, map, user) redirect to(Entity::REST.entity_map_url(new_id, entity_type, column)) end get '/entity_map/rank_products' do map1 = consume_parameter :map1 map2 = consume_parameter :map2 map1 = Entity::REST.restore_element(map1) map2 = Entity::REST.restore_element(map2) entity_type = consume_parameter :entity_type column = consume_parameter :column entity_type = Entity::REST.restore_element(entity_type) column = Entity::REST.restore_element(column) file1 = Entity::Map.map_file(entity_type.split(":").first, column, map1, user) file1 = Entity::Map.map_file(entity_type.split(":").first, column, map1, nil) unless File.exists? file1 tsv1 = TSV.open(file1) file2 = Entity::Map.map_file(entity_type.split(":").first, column, map2, user) file2 = Entity::Map.map_file(entity_type.split(":").first, column, map2, nil) unless File.exists? file2 tsv2 = TSV.open(file2) tsv1.attach tsv2, :fields => tsv2.fields new = TSV.setup(tsv1.rank_product(tsv1.fields), :key_field => tsv1.key_field, :fields => ["Log rank-product"], :type => :single, :cast => :to_f) new.entity_options = tsv1.entity_options new.namespace = tsv1.namespace new_id = "Rank products of #{ map1 } ~ #{ map2 }" if new_id.length > 200 new_id = "Rank products of #{ Misc.digest(map1) } ~ #{ Misc.digest(map2) }" end column = 'Log rank-product' Entity::Map.save_map(entity_type, column, new_id, new, user) redirect to(Entity::REST.entity_map_url(new_id, entity_type, column)) end #{{{{{{{{{{{{{{ #{{{ FAVOURITES #{{{{{{{{{{{{{{ #{{{ Favourite entities post '/add_favourite_entity/:entity_type/:entity' do entity_type = consume_parameter :entity_type entity = consume_parameter :entity entity_type = Entity::REST.restore_element(entity_type) entity = setup_entity(entity_type, entity, @clean_params) add_favourite_entity(entity) halt 200 end post '/remove_favourite_entity/:entity_type/:entity' do entity_type = consume_parameter :entity_type entity = consume_parameter :entity entity_type = Entity::REST.restore_element(entity_type) entity = setup_entity(entity_type, entity, @clean_params) remove_favourite_entity(entity) halt 200 end get '/favourite_entities' do content_type "application/json" favs = {} favourite_entities.each{|type, list| type_favs = {} list.each do |entity| info = entity.info info.delete :annotation_types type_favs[entity] = {:info => info, :link => entity.link} end favs[type] = type_favs } favs.to_json end #{{{ Favourite entity lists post '/add_favourite_entity_list/:entity_type/:list' do entity_type = consume_parameter :entity_type list = consume_parameter :list list = Entity::REST.restore_element(list) entity_type = Entity::REST.restore_element(entity_type).split(":").first add_favourite_entity_list(entity_type, list) halt 200 end post '/remove_favourite_entity_list/:entity_type/:list' do entity_type = consume_parameter :entity_type list = consume_parameter :list list = Entity::REST.restore_element(list) entity_type = Entity::REST.restore_element(entity_type).split(":").first remove_favourite_entity_list(entity_type, list) halt 200 end get '/favourite_entity_lists' do content_type "application/json" favs = favourite_entity_lists favs.to_json end #{{{ Favourite entity maps post '/add_favourite_entity_map/:entity_type/:column/:map' do entity_type = consume_parameter :entity_type column = consume_parameter :column map = consume_parameter :map map = Entity::REST.restore_element(map) entity_type = Entity::REST.restore_element(entity_type).split(":").first column = Entity::REST.restore_element(column) add_favourite_entity_map(entity_type, column, map) halt 200 end post '/remove_favourite_entity_map/:entity_type/:column/:map' do entity_type = consume_parameter :entity_type column = consume_parameter :column map = consume_parameter :map map = Entity::REST.restore_element(map) entity_type = Entity::REST.restore_element(entity_type).split(":").first column = Entity::REST.restore_element(column) remove_favourite_entity_map(entity_type, column, map) halt 200 end get '/favourite_entity_maps' do content_type "application/json" favs = favourite_entity_maps favs.to_json end end end end end