Merge branch 'master' into 3112-report-bug. Also, break search testing into a separat...
[arvados.git] / apps / workbench / app / controllers / actions_controller.rb
1 class ActionsController < ApplicationController
2
3   @@exposed_actions = {}
4   def self.expose_action method, &block
5     @@exposed_actions[method] = true
6     define_method method, block
7   end
8
9   def model_class
10     ArvadosBase::resource_class_for_uuid(params[:uuid])
11   end
12
13   def show
14     @object = model_class.andand.find(params[:uuid])
15     if @object.is_a? Link and
16         @object.link_class == 'name' and
17         ArvadosBase::resource_class_for_uuid(@object.head_uuid) == Collection
18       redirect_to collection_path(id: @object.uuid)
19     elsif @object
20       redirect_to @object
21     else
22       raise ActiveRecord::RecordNotFound
23     end
24   end
25
26   def post
27     params.keys.collect(&:to_sym).each do |param|
28       if @@exposed_actions[param]
29         return self.send(param)
30       end
31     end
32     redirect_to :back
33   end
34
35   expose_action :copy_selections_into_project do
36     move_or_copy :copy
37   end
38
39   expose_action :move_selections_into_project do
40     move_or_copy :move
41   end
42
43   def move_or_copy action
44     uuids_to_add = params["selection"]
45     uuids_to_add = [ uuids_to_add ] unless uuids_to_add.is_a? Array
46     uuids_to_add.
47       collect { |x| ArvadosBase::resource_class_for_uuid(x) }.
48       uniq.
49       each do |resource_class|
50       resource_class.filter([['uuid','in',uuids_to_add]]).each do |src|
51         if resource_class == Collection
52           dst = Link.new(owner_uuid: @object.uuid,
53                          tail_uuid: @object.uuid,
54                          head_uuid: src.uuid,
55                          link_class: 'name',
56                          name: src.uuid)
57         else
58           case action
59           when :copy
60             dst = src.dup
61             if dst.respond_to? :'name='
62               if dst.name
63                 dst.name = "Copy of #{dst.name}"
64               else
65                 dst.name = "Copy of unnamed #{dst.class_for_display.downcase}"
66               end
67             end
68           when :move
69             dst = src
70           else
71             raise ArgumentError.new "Unsupported action #{action}"
72           end
73           dst.owner_uuid = @object.uuid
74           dst.tail_uuid = @object.uuid if dst.class == Link
75         end
76         begin
77           dst.save!
78         rescue
79           dst.name += " (#{Time.now.localtime})" if dst.respond_to? :name=
80           dst.save!
81         end
82       end
83     end
84     redirect_to @object
85   end
86
87   def arv_normalize mt, *opts
88     r = ""
89     IO.popen(['arv-normalize'] + opts, 'w+b') do |io|
90       io.write mt
91       io.close_write
92       while buf = io.read(2**16)
93         r += buf
94       end
95     end
96     r
97   end
98
99   expose_action :combine_selected_files_into_collection do
100     lst = []
101     files = []
102     params["selection"].each do |s|
103       a = ArvadosBase::resource_class_for_uuid s
104       m = nil
105       if a == Link
106         begin
107           m = CollectionsHelper.match(Link.find(s).head_uuid)
108         rescue
109         end
110       else
111         m = CollectionsHelper.match(s)
112       end
113
114       if m and m[1] and m[2]
115         lst.append(m[1] + m[2])
116         files.append(m)
117       end
118     end
119
120     collections = Collection.where(uuid: lst)
121
122     chash = {}
123     collections.each do |c|
124       c.reload()
125       chash[c.uuid] = c
126     end
127
128     combined = ""
129     files.each do |m|
130       mt = chash[m[1]+m[2]].manifest_text
131       if m[4]
132         combined += arv_normalize mt, '--extract', m[4][1..-1]
133       else
134         combined += chash[m[1]+m[2]].manifest_text
135       end
136     end
137
138     normalized = arv_normalize combined
139     normalized_stripped = arv_normalize combined, '--strip'
140
141     require 'digest/md5'
142
143     d = Digest::MD5.new()
144     d << normalized_stripped
145     newuuid = "#{d.hexdigest}+#{normalized_stripped.length}"
146
147     env = Hash[ENV].
148       merge({
149               'ARVADOS_API_HOST' =>
150               arvados_api_client.arvados_v1_base.
151               sub(/\/arvados\/v1/, '').
152               sub(/^https?:\/\//, ''),
153               'ARVADOS_API_TOKEN' => Thread.current[:arvados_api_token],
154               'ARVADOS_API_HOST_INSECURE' =>
155               Rails.configuration.arvados_insecure_https ? 'true' : 'false'
156             })
157
158     IO.popen([env, 'arv-put', '--raw'], 'w+b') do |io|
159       io.write normalized_stripped
160       io.close_write
161       while buf = io.read(2**16)
162       end
163     end
164
165     newc = Collection.new({:uuid => newuuid, :manifest_text => normalized})
166     newc.save!
167
168     chash.each do |k,v|
169       l = Link.new({
170                      tail_uuid: k,
171                      head_uuid: newuuid,
172                      link_class: "provenance",
173                      name: "provided"
174                    })
175       l.save!
176     end
177
178     redirect_to controller: 'collections', action: :show, id: newc.uuid
179   end
180
181   def report_issue_popup
182     @popup_params = params
183     respond_to do |format|
184       format.js
185       format.html
186     end
187   end
188
189   def report_issue
190     $stderr.puts "Issue being reported with these parameters: #{params.inspect}"
191     logger.warn "Issue being reported with these parameters: #{params.inspect}"
192
193     respond_to do |format|
194       IssueReporter.send_report(current_user, params).deliver
195       format.js
196     end
197   end
198
199 end