3654: add a default name to newly created combined collection
[arvados.git] / apps / workbench / app / controllers / actions_controller.rb
index c443c2196e372414c1d6e3361dc8e12f294c9527..347644bdbd141092051173315e52afcc3548d03f 100644 (file)
 class ActionsController < ApplicationController
-  def combine_selected_files_into_collection
-    lst = []
-    files = []
-    params["selection"].each do |s|
-      m = CollectionsHelper.match(s)
-      if m[1] and m[2]
-        lst.append(m[1] + m[2])
-        files.append(m)
-      end
-    end
 
-    collections = Collection.where(uuid: lst)
+  skip_filter :require_thread_api_token, only: [:report_issue_popup, :report_issue]
+  skip_filter :check_user_agreements, only: [:report_issue_popup, :report_issue]
 
-    chash = {}
-    collections.each do |c|
-      c.reload()
-      chash[c.uuid] = c
-    end
+  @@exposed_actions = {}
+  def self.expose_action method, &block
+    @@exposed_actions[method] = true
+    define_method method, block
+  end
 
-    combined = ""
-    files.each do |m|
-      mt = chash[m[1]+m[2]].manifest_text
-      if m[4]
-        IO.popen(['arv-normalize', '--extract', m[4][1..-1]], 'w+b') do |io|
-          io.write mt
-          io.close_write
-          while buf = io.read(2**20)
-            combined += buf
-          end
-        end
-      else
-        combined += chash[m[1]+m[2]].manifest_text
-      end
+  def model_class
+    ArvadosBase::resource_class_for_uuid(params[:uuid])
+  end
+
+  def show
+    @object = model_class.andand.find(params[:uuid])
+    if @object.is_a? Link and
+        @object.link_class == 'name' and
+        ArvadosBase::resource_class_for_uuid(@object.head_uuid) == Collection
+      redirect_to collection_path(id: @object.uuid)
+    elsif @object
+      redirect_to @object
+    else
+      raise ActiveRecord::RecordNotFound
     end
+  end
 
-    normalized = ''
-    IO.popen(['arv-normalize'], 'w+b') do |io|
-      io.write combined
-      io.close_write
-      while buf = io.read(2**20)
-        normalized += buf
+  def post
+    params.keys.collect(&:to_sym).each do |param|
+      if @@exposed_actions[param]
+        return self.send(param)
       end
     end
+    redirect_to :back
+  end
+
+  expose_action :copy_selections_into_project do
+    move_or_copy :copy
+  end
 
-    require 'digest/md5'
+  expose_action :move_selections_into_project do
+    move_or_copy :move
+  end
 
-    d = Digest::MD5.new()
-    d << normalized
-    newuuid = "#{d.hexdigest}+#{normalized.length}"
+  def move_or_copy action
+    uuids_to_add = params["selection"]
+    uuids_to_add = [ uuids_to_add ] unless uuids_to_add.is_a? Array
+    uuids_to_add.
+      collect { |x| ArvadosBase::resource_class_for_uuid(x) }.
+      uniq.
+      each do |resource_class|
+      resource_class.filter([['uuid','in',uuids_to_add]]).each do |src|
+        if resource_class == Collection and not Collection.attribute_info.include?(:name)
+          dst = Link.new(owner_uuid: @object.uuid,
+                         tail_uuid: @object.uuid,
+                         head_uuid: src.uuid,
+                         link_class: 'name',
+                         name: src.uuid)
+        else
+          case action
+          when :copy
+            dst = src.dup
+            if dst.respond_to? :'name='
+              if dst.name
+                dst.name = "Copy of #{dst.name}"
+              else
+                dst.name = "Copy of unnamed #{dst.class_for_display.downcase}"
+              end
+            end
+            if resource_class == Collection
+              dst.manifest_text = Collection.select([:manifest_text]).where(uuid: src.uuid).first.manifest_text
+            end
+          when :move
+            dst = src
+          else
+            raise ArgumentError.new "Unsupported action #{action}"
+          end
+          dst.owner_uuid = @object.uuid
+          dst.tail_uuid = @object.uuid if dst.class == Link
+        end
+        begin
+          dst.save!
+        rescue
+          dst.name += " (#{Time.now.localtime})" if dst.respond_to? :name=
+          dst.save!
+        end
+      end
+    end
+    redirect_to @object
+  end
 
+  def arv_normalize mt, *opts
+    r = ""
     env = Hash[ENV].
-      merge({
-              'ARVADOS_API_HOST' =>
-              $arvados_api_client.arvados_v1_base.
+      merge({'ARVADOS_API_HOST' =>
+              arvados_api_client.arvados_v1_base.
               sub(/\/arvados\/v1/, '').
               sub(/^https?:\/\//, ''),
-              'ARVADOS_API_TOKEN' => Thread.current[:arvados_api_token],
+              'ARVADOS_API_TOKEN' => 'x',
               'ARVADOS_API_HOST_INSECURE' =>
               Rails.configuration.arvados_insecure_https ? 'true' : 'false'
             })
-
-    IO.popen([env, 'arv-put', '--raw'], 'w+b') do |io|
-      io.write normalized
+    IO.popen([env, 'arv-normalize'] + opts, 'w+b') do |io|
+      io.write mt
       io.close_write
-      while buf = io.read(2**20)
+      while buf = io.read(2**16)
+        r += buf
+      end
+    end
+    r
+  end
+
+  expose_action :combine_selected_files_into_collection do
+    uuids = []
+    pdhs = []
+    files = []
+    params["selection"].each do |s|
+      a = ArvadosBase::resource_class_for_uuid s
+      if a == Link
+        begin
+          if (m = CollectionsHelper.match(Link.find(s).head_uuid))
+            pdhs.append(m[1] + m[2])
+            files.append(m)
+          end
+        rescue
+        end
+      elsif (m = CollectionsHelper.match(s))
+        pdhs.append(m[1] + m[2])
+        files.append(m)
+      elsif (m = CollectionsHelper.match_uuid_with_optional_filepath(s))
+        uuids.append(m[1])
+        files.append(m)
+      end
+    end
+
+    pdhs = pdhs.uniq
+    uuids = uuids.uniq
+    chash = {}
+
+    Collection.select([:uuid, :manifest_text]).where(uuid: uuids).each do |c|
+      chash[c.uuid] = c
+    end
 
+    Collection.select([:portable_data_hash, :manifest_text]).where(portable_data_hash: pdhs).each do |c|
+      chash[c.portable_data_hash] = c
+    end
+
+    combined = ""
+    files.each do |m|
+      mt = chash[m[1]+m[2]].andand.manifest_text
+      if not m[4].nil? and m[4].size > 1
+        combined += arv_normalize mt, '--extract', m[4][1..-1]
+      else
+        combined += mt
       end
     end
 
-    newc = Collection.new({:uuid => newuuid, :manifest_text => normalized})
+    normalized = arv_normalize combined
+    newc = Collection.new({:manifest_text => normalized})
+    newc.name = newc.name || "Collection created at #{Time.now.localtime}"
     newc.save!
 
     chash.each do |k,v|
       l = Link.new({
-                     tail_kind: "arvados#Collection",
                      tail_uuid: k,
-                     head_kind: "arvados#Collection", 
-                     head_uuid: newuuid,
+                     head_uuid: newc.uuid,
                      link_class: "provenance",
                      name: "provided"
                    })
       l.save!
     end
 
-    '/collections/' + newc.uuid
+    action_data = JSON.parse(params['action_data']) if params['action_data']
+    if action_data && action_data['selection_param'].eql?('project')
+      redirect_to :back
+    else
+      redirect_to url_for(controller: 'collections', action: :show, id: newc.uuid)
+    end
+  end
+
+  def report_issue_popup
+    respond_to do |format|
+      format.js
+      format.html
+    end
   end
 
-  def post
-    if params["combine_selected_files_into_collection"]
-      redirect_to combine_selected_files_into_collection
-    else
-      redirect_to :back
+  def report_issue
+    logger.warn "report_issue: #{params.inspect}"
+
+    respond_to do |format|
+      IssueReporter.send_report(current_user, params).deliver
+      format.js {render nothing: true}
     end
   end
+
 end