Merge branch '3235-top-nav-site-search' refs #3235
[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.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     else
20       redirect_to @object
21     end
22   end
23
24   def post
25     params.keys.collect(&:to_sym).each do |param|
26       if @@exposed_actions[param]
27         return self.send(param)
28       end
29     end
30     redirect_to :back
31   end
32
33   expose_action :copy_selections_into_project do
34     move_or_copy :copy
35   end
36
37   expose_action :move_selections_into_project do
38     move_or_copy :move
39   end
40
41   def move_or_copy action
42     uuids_to_add = params["selection"]
43     uuids_to_add.
44       collect { |x| ArvadosBase::resource_class_for_uuid(x) }.
45       uniq.
46       each do |resource_class|
47       resource_class.filter([['uuid','in',uuids_to_add]]).each do |src|
48         if resource_class == Collection
49           dst = Link.new(owner_uuid: @object.uuid,
50                          tail_uuid: @object.uuid,
51                          head_uuid: src.uuid,
52                          link_class: 'name',
53                          name: src.uuid)
54         else
55           case action
56           when :copy
57             dst = src.dup
58             if dst.respond_to? :'name='
59               if dst.name
60                 dst.name = "Copy of #{dst.name}"
61               else
62                 dst.name = "Copy of unnamed #{dst.class_for_display.downcase}"
63               end
64             end
65           when :move
66             dst = src
67           else
68             raise ArgumentError.new "Unsupported action #{action}"
69           end
70           dst.owner_uuid = @object.uuid
71           dst.tail_uuid = @object.uuid if dst.class == Link
72         end
73         begin
74           dst.save!
75         rescue
76           dst.name += " (#{Time.now.localtime})" if dst.respond_to? :name=
77           dst.save!
78         end
79       end
80     end
81     redirect_to @object
82   end
83
84   def arv_normalize mt, *opts
85     r = ""
86     IO.popen(['arv-normalize'] + opts, 'w+b') do |io|
87       io.write mt
88       io.close_write
89       while buf = io.read(2**16)
90         r += buf
91       end
92     end
93     r
94   end
95
96   expose_action :combine_selected_files_into_collection do
97     lst = []
98     files = []
99     params["selection"].each do |s|
100       a = ArvadosBase::resource_class_for_uuid s
101       m = nil
102       if a == Link
103         begin
104           m = CollectionsHelper.match(Link.find(s).head_uuid)
105         rescue
106         end
107       else
108         m = CollectionsHelper.match(s)
109       end
110
111       if m and m[1] and m[2]
112         lst.append(m[1] + m[2])
113         files.append(m)
114       end
115     end
116
117     collections = Collection.where(uuid: lst)
118
119     chash = {}
120     collections.each do |c|
121       c.reload()
122       chash[c.uuid] = c
123     end
124
125     combined = ""
126     files.each do |m|
127       mt = chash[m[1]+m[2]].manifest_text
128       if m[4]
129         combined += arv_normalize mt, '--extract', m[4][1..-1]
130       else
131         combined += chash[m[1]+m[2]].manifest_text
132       end
133     end
134
135     normalized = arv_normalize combined
136     normalized_stripped = arv_normalize combined, '--strip'
137
138     require 'digest/md5'
139
140     d = Digest::MD5.new()
141     d << normalized_stripped
142     newuuid = "#{d.hexdigest}+#{normalized_stripped.length}"
143
144     env = Hash[ENV].
145       merge({
146               'ARVADOS_API_HOST' =>
147               arvados_api_client.arvados_v1_base.
148               sub(/\/arvados\/v1/, '').
149               sub(/^https?:\/\//, ''),
150               'ARVADOS_API_TOKEN' => Thread.current[:arvados_api_token],
151               'ARVADOS_API_HOST_INSECURE' =>
152               Rails.configuration.arvados_insecure_https ? 'true' : 'false'
153             })
154
155     IO.popen([env, 'arv-put', '--raw'], 'w+b') do |io|
156       io.write normalized_stripped
157       io.close_write
158       while buf = io.read(2**16)
159       end
160     end
161
162     newc = Collection.new({:uuid => newuuid, :manifest_text => normalized})
163     newc.save!
164
165     chash.each do |k,v|
166       l = Link.new({
167                      tail_uuid: k,
168                      head_uuid: newuuid,
169                      link_class: "provenance",
170                      name: "provided"
171                    })
172       l.save!
173     end
174
175     redirect_to controller: 'collections', action: :show, id: newc.uuid
176   end
177
178 end