X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/b3eb8176f8d060b0e4652cae8e041c6bf2b7103e..b0cf100405e0dd7e4913194cd88b71ff74cf1773:/apps/workbench/app/controllers/actions_controller.rb diff --git a/apps/workbench/app/controllers/actions_controller.rb b/apps/workbench/app/controllers/actions_controller.rb index 9f2cfb09f3..7737a3cfe4 100644 --- a/apps/workbench/app/controllers/actions_controller.rb +++ b/apps/workbench/app/controllers/actions_controller.rb @@ -1,5 +1,8 @@ class ActionsController < ApplicationController + skip_filter :require_thread_api_token, only: [:report_issue_popup, :report_issue] + skip_filter :check_user_agreements, only: [:report_issue_popup, :report_issue] + @@exposed_actions = {} def self.expose_action method, &block @@exposed_actions[method] = true @@ -11,13 +14,15 @@ class ActionsController < ApplicationController end def show - @object = model_class.find(params[:uuid]) + @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) - else + elsif @object redirect_to @object + else + raise ActiveRecord::RecordNotFound end end @@ -40,12 +45,13 @@ class ActionsController < ApplicationController def move_or_copy action uuids_to_add = params["selection"] - uuids_to_add. + uuids_to_add = [ uuids_to_add ] unless uuids_to_add.is_a? Array + resource_classes = uuids_to_add. collect { |x| ArvadosBase::resource_class_for_uuid(x) }. - uniq. - each do |resource_class| + uniq + resource_classes.each do |resource_class| resource_class.filter([['uuid','in',uuids_to_add]]).each do |src| - if resource_class == Collection + 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, @@ -62,6 +68,9 @@ class ActionsController < ApplicationController 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 @@ -78,12 +87,31 @@ class ActionsController < ApplicationController end end end - redirect_to @object + if (resource_classes == [Collection] and + @object.is_a? Group and + @object.group_class == 'project') + # In the common case where only collections are copied/moved + # into a project, it's polite to land on the collections tab on + # the destination project. + redirect_to project_url(@object.uuid, anchor: 'Data_collections') + else + # Otherwise just land on the default (Description) tab. + redirect_to @object + end end def arv_normalize mt, *opts r = "" - IO.popen(['arv-normalize'] + opts, 'w+b') do |io| + env = Hash[ENV]. + merge({'ARVADOS_API_HOST' => + arvados_api_client.arvados_v1_base. + sub(/\/arvados\/v1/, ''). + sub(/^https?:\/\//, ''), + 'ARVADOS_API_TOKEN' => 'x', + 'ARVADOS_API_HOST_INSECURE' => + Rails.configuration.arvados_insecure_https ? 'true' : 'false' + }) + IO.popen([env, 'arv-normalize'] + opts, 'w+b') do |io| io.write mt io.close_write while buf = io.read(2**16) @@ -94,85 +122,149 @@ class ActionsController < ApplicationController end expose_action :combine_selected_files_into_collection do - lst = [] + uuids = [] + pdhs = [] files = [] params["selection"].each do |s| a = ArvadosBase::resource_class_for_uuid s - m = nil if a == Link begin - m = CollectionsHelper.match(Link.find(s).head_uuid) + if (m = CollectionsHelper.match(Link.find(s).head_uuid)) + pdhs.append(m[1] + m[2]) + files.append(m) + end rescue end - else - m = CollectionsHelper.match(s) - end - - if m and m[1] and m[2] - lst.append(m[1] + m[2]) + 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 - collections = Collection.where(uuid: lst) - + pdhs = pdhs.uniq + uuids = uuids.uniq chash = {} - collections.each do |c| - c.reload() + + 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_in_dirs = {} files.each do |m| - mt = chash[m[1]+m[2]].manifest_text - if m[4] - combined += arv_normalize mt, '--extract', m[4][1..-1] + mt = chash[m[1]+m[2]].andand.manifest_text + if not m[4].nil? and m[4].size > 1 + manifest_files = files_in_dirs['.'] + if !manifest_files + manifest_files = [] + files_in_dirs['.'] = manifest_files + end + manifest_file = m[4].split('/')[-1] + uniq_file = derive_unique_filename(manifest_file, manifest_files) + normalized = arv_normalize mt, '--extract', ".#{m[4]}" + normalized = normalized.gsub(/(\d+:\d+:)(#{Regexp.quote manifest_file})/) {|s| "#{$1}#{uniq_file}" } + combined += normalized + manifest_files << uniq_file else - combined += chash[m[1]+m[2]].manifest_text + mt = arv_normalize mt + manifest_streams = mt.split "\n" + adjusted_streams = [] + manifest_streams.each do |stream| + manifest_parts = stream.split + adjusted_parts = [] + manifest_files = files_in_dirs[manifest_parts[0]] + if !manifest_files + manifest_files = [] + files_in_dirs[manifest_parts[0]] = manifest_files + end + + manifest_parts.each do |part| + part_match = /(\d+:\d+:)(\S+)/.match(part) + if part_match + uniq_file = derive_unique_filename(part_match[2], manifest_files) + adjusted_parts << "#{part_match[1]}#{uniq_file}" + manifest_files << uniq_file + else + adjusted_parts << part + end + end + adjusted_streams << adjusted_parts.join(' ') + end + adjusted_streams.each do |stream| + combined += (stream + "\n") + end end end normalized = arv_normalize combined - normalized_stripped = arv_normalize combined, '--strip' - - require 'digest/md5' - - d = Digest::MD5.new() - d << normalized_stripped - newuuid = "#{d.hexdigest}+#{normalized_stripped.length}" - - env = Hash[ENV]. - 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_HOST_INSECURE' => - Rails.configuration.arvados_insecure_https ? 'true' : 'false' - }) + newc = Collection.new({:manifest_text => normalized}) + newc.name = newc.name || "Collection created at #{Time.now.localtime}" - IO.popen([env, 'arv-put', '--raw'], 'w+b') do |io| - io.write normalized_stripped - io.close_write - while buf = io.read(2**16) + # set owner_uuid to current project, provided it is writable + current_project_writable = false + action_data = JSON.parse(params['action_data']) if params['action_data'] + if action_data && action_data['current_project_uuid'] + current_project = Group.find(action_data['current_project_uuid']) rescue nil + if (current_project && current_project.writable_by.andand.include?(current_user.uuid)) + newc.owner_uuid = action_data['current_project_uuid'] + current_project_writable = true end end - newc = Collection.new({:uuid => newuuid, :manifest_text => normalized}) newc.save! chash.each do |k,v| l = Link.new({ tail_uuid: k, - head_uuid: newuuid, + head_uuid: newc.uuid, link_class: "provenance", name: "provided" }) l.save! end - redirect_to controller: 'collections', action: :show, id: newc.uuid + msg = current_project_writable ? + "Created new collection in the project #{current_project.name}." : + "Created new collection in your Home project." + + redirect_to newc, flash: {'message' => msg} + end + + def report_issue_popup + respond_to do |format| + format.js + format.html + end + end + + 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 + + protected + + def derive_unique_filename filename, manifest_files + filename_parts = filename.split('.') + filename_part = filename_parts[0] + counter = 1 + while true + return filename if !manifest_files.include? filename + filename_parts[0] = filename_part + "(" + counter.to_s + ")" + filename = filename_parts.join('.') + counter += 1 + end end end