With where={"any":["contains",X]}, search all text and string columns.
[arvados.git] / apps / workbench / app / controllers / collections_controller.rb
1 class CollectionsController < ApplicationController
2   skip_before_filter :find_object_by_uuid, :only => [:graph]
3   skip_before_filter :check_user_agreements, :only => [:show_file]
4
5   def graph
6     index
7   end
8
9   def index
10     if params[:search].andand.length.andand > 0
11       tags = Link.where(any: ['contains', params[:search]])
12       @collections = (Collection.where(uuid: tags.collect(&:head_uuid)) |
13                       Collection.where(any: ['contains', params[:search]])).
14         uniq { |c| c.uuid }
15     else
16       @collections = Collection.limit(100)
17     end
18     @links = Link.limit(1000).
19       where(head_uuid: @collections.collect(&:uuid))
20     @collection_info = {}
21     @collections.each do |c|
22       @collection_info[c.uuid] = {
23         tags: [],
24         wanted: false,
25         wanted_by_me: false,
26         provenance: [],
27         links: []
28       }
29     end
30     @links.each do |link|
31       @collection_info[link.head_uuid] ||= {}
32       info = @collection_info[link.head_uuid]
33       case link.link_class
34       when 'tag'
35         info[:tags] << link.name
36       when 'resources'
37         info[:wanted] = true
38         info[:wanted_by_me] ||= link.tail_uuid == current_user.uuid
39       when 'provenance'
40         info[:provenance] << link.name
41       end
42       info[:links] << link
43     end
44     @request_url = request.url
45   end
46
47   def show_file
48     opts = params.merge(arvados_api_token: Thread.current[:arvados_api_token])
49     if r = params[:file].match(/(\.\w+)/)
50       ext = r[1]
51     end
52     self.response.headers['Content-Type'] =
53       Rack::Mime::MIME_TYPES[ext] || 'application/octet-stream'
54     self.response.headers['Content-Length'] = params[:size] if params[:size]
55     self.response.headers['Content-Disposition'] = params[:disposition] if params[:disposition]
56     self.response_body = FileStreamer.new opts
57   end
58
59   def show
60     return super if !@object
61     @provenance = []
62     @output2job = {}
63     @output2colorindex = {}
64     @sourcedata = {params[:uuid] => {uuid: params[:uuid]}}
65     @protected = {}
66
67     colorindex = -1
68     any_hope_left = true
69     while any_hope_left
70       any_hope_left = false
71       Job.where(output: @sourcedata.keys).sort_by { |a| a.finished_at || a.created_at }.reverse.each do |job|
72         if !@output2colorindex[job.output]
73           any_hope_left = true
74           @output2colorindex[job.output] = (colorindex += 1) % 10
75           @provenance << {job: job, output: job.output}
76           @sourcedata.delete job.output
77           @output2job[job.output] = job
78           job.dependencies.each do |new_source_data|
79             unless @output2colorindex[new_source_data]
80               @sourcedata[new_source_data] = {uuid: new_source_data}
81             end
82           end
83         end
84       end
85     end
86
87     Link.where(head_uuid: @sourcedata.keys | @output2job.keys).each do |link|
88       if link.link_class == 'resources' and link.name == 'wants'
89         @protected[link.head_uuid] = true
90       end
91     end
92     Link.where(tail_uuid: @sourcedata.keys).each do |link|
93       if link.link_class == 'data_origin'
94         @sourcedata[link.tail_uuid][:data_origins] ||= []
95         @sourcedata[link.tail_uuid][:data_origins] << [link.name, link.head_kind, link.head_uuid]
96       end
97     end
98     Collection.where(uuid: @sourcedata.keys).each do |collection|
99       if @sourcedata[collection.uuid]
100         @sourcedata[collection.uuid][:collection] = collection
101       end
102     end
103   end
104
105   protected
106   class FileStreamer
107     def initialize(opts={})
108       @opts = opts
109     end
110     def each
111       return unless @opts[:uuid] && @opts[:file]
112       env = Hash[ENV].
113         merge({
114                 'ARVADOS_API_HOST' =>
115                 $arvados_api_client.arvados_v1_base.
116                 sub(/\/arvados\/v1/, '').
117                 sub(/^https?:\/\//, ''),
118                 'ARVADOS_API_TOKEN' =>
119                 @opts[:arvados_api_token],
120                 'ARVADOS_API_HOST_INSECURE' =>
121                 Rails.configuration.arvados_insecure_https ? 'true' : 'false'
122               })
123       IO.popen([env, 'arv-get', "#{@opts[:uuid]}/#{@opts[:file]}"],
124                'rb') do |io|
125         while buf = io.read(2**20)
126           yield buf
127         end
128       end
129       Rails.logger.warn("#{@opts[:uuid]}/#{@opts[:file]}: #{$?}") if $? != 0
130     end
131   end
132 end