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