From: Peter Amstutz Date: Thu, 22 May 2014 20:30:34 +0000 (-0400) Subject: Merge remote-tracking branch 'origin/master' into 2044-share-button X-Git-Tag: 1.1.0~2596^2~4 X-Git-Url: https://git.arvados.org/arvados.git/commitdiff_plain/675794872a5d064cf0a8177d662555c04b0dae51 Merge remote-tracking branch 'origin/master' into 2044-share-button --- 675794872a5d064cf0a8177d662555c04b0dae51 diff --cc apps/workbench/app/controllers/collections_controller.rb index 509b9f4cb2,3b4943f588..3e981e10d8 --- a/apps/workbench/app/controllers/collections_controller.rb +++ b/apps/workbench/app/controllers/collections_controller.rb @@@ -110,99 -120,44 +120,76 @@@ class CollectionsController < Applicati self.response_body = file_enumerator opts end ++ def sharing_scopes ++ ["GET /arvados/v1/collections/#{@object.uuid}", "GET /arvados/v1/keep_services"] ++ end ++ + def search_scopes - ApiClientAuthorization.where(filters: [['scopes', '=', ["GET /arvados/v1/collections/#{@object.uuid}", "GET /arvados/v1/collections/#{@object.uuid}/"]]]) ++ ApiClientAuthorization.where(filters: [['scopes', '=', sharing_scopes]]) + end + def show return super if !@object - @provenance = [] - @output2job = {} - @output2colorindex = {} - @sourcedata = {params[:uuid] => {uuid: params[:uuid]}} - @protected = {} - @search_sharing = search_scopes.select { |s| s.scopes != ['all'] } - - colorindex = -1 - any_hope_left = true - while any_hope_left - any_hope_left = false - Job.where(output: @sourcedata.keys).sort_by { |a| a.finished_at || a.created_at }.reverse.each do |job| - if !@output2colorindex[job.output] - any_hope_left = true - @output2colorindex[job.output] = (colorindex += 1) % 10 - @provenance << {job: job, output: job.output} - @sourcedata.delete job.output - @output2job[job.output] = job - job.dependencies.each do |new_source_data| - unless @output2colorindex[new_source_data] - @sourcedata[new_source_data] = {uuid: new_source_data} - end - end - end - end - end - - Link.where(head_uuid: @sourcedata.keys | @output2job.keys).each do |link| - if link.link_class == 'resources' and link.name == 'wants' - @protected[link.head_uuid] = true - if link.tail_uuid == current_user.uuid - @is_persistent = true - end + if current_user + jobs_with = lambda do |conds| + Job.limit(RELATION_LIMIT).where(conds) + .results.sort_by { |j| j.finished_at || j.created_at } end + @output_of = jobs_with.call(output: @object.uuid) + @log_of = jobs_with.call(log: @object.uuid) + folder_links = Link.limit(RELATION_LIMIT).order("modified_at DESC") + .where(head_uuid: @object.uuid, link_class: 'name').results + folder_hash = Group.where(uuid: folder_links.map(&:tail_uuid)).to_hash + @folders = folder_links.map { |link| folder_hash[link.tail_uuid] } + @permissions = Link.limit(RELATION_LIMIT).order("modified_at DESC") + .where(head_uuid: @object.uuid, link_class: 'permission', + name: 'can_read').results + @logs = Log.limit(RELATION_LIMIT).order("created_at DESC") + .where(object_uuid: @object.uuid).results + @is_persistent = Link.limit(1) + .where(head_uuid: @object.uuid, tail_uuid: current_user.uuid, + link_class: 'resources', name: 'wants') + .results.any? ++ @search_sharing = search_scopes.select { |s| s.scopes != ['all'] } end - Link.where(tail_uuid: @sourcedata.keys).each do |link| - if link.link_class == 'data_origin' - @sourcedata[link.tail_uuid][:data_origins] ||= [] - @sourcedata[link.tail_uuid][:data_origins] << [link.name, link.head_uuid] - end - end - Collection.where(uuid: @sourcedata.keys).each do |collection| - if @sourcedata[collection.uuid] - @sourcedata[collection.uuid][:collection] = collection - end - end - - Collection.where(uuid: @object.uuid).each do |u| - @prov_svg = ProvenanceHelper::create_provenance_graph(u.provenance, "provenance_svg", - {:request => request, - :direction => :bottom_up, - :combine_jobs => :script_only}) rescue nil - @used_by_svg = ProvenanceHelper::create_provenance_graph(u.used_by, "used_by_svg", - {:request => request, - :direction => :top_down, - :combine_jobs => :script_only, - :pdata_only => true}) rescue nil - end + @prov_svg = ProvenanceHelper::create_provenance_graph(@object.provenance, "provenance_svg", + {:request => request, + :direction => :bottom_up, + :combine_jobs => :script_only}) rescue nil + @used_by_svg = ProvenanceHelper::create_provenance_graph(@object.used_by, "used_by_svg", + {:request => request, + :direction => :top_down, + :combine_jobs => :script_only, + :pdata_only => true}) rescue nil end + def sharing_popup + @search_sharing = search_scopes.select { |s| s.scopes != ['all'] } + respond_to do |format| + format.html + format.js + end + end + + def share - a = ApiClientAuthorization.create(scopes: ["GET /arvados/v1/collections/#{@object.uuid}", "GET /arvados/v1/collections/#{@object.uuid}/"]) ++ a = ApiClientAuthorization.create(scopes: sharing_scopes) + @search_sharing = search_scopes.select { |s| s.scopes != ['all'] } + render 'sharing_popup' + end + + def unshare + @search_sharing = search_scopes.select { |s| s.scopes != ['all'] } + @search_sharing.each do |s| + s.destroy + end + @search_sharing = search_scopes.select { |s| s.scopes != ['all'] } + render 'sharing_popup' + end + protected - def find_usable_token - # Iterate over every token available to make it the current token and + def find_usable_token(token_list) + # Iterate over every given token to make it the current token and # yield the given block. # If the block succeeds, return the token it used. # Otherwise, render an error response based on the most specific diff --cc apps/workbench/app/views/collections/_sharing_button.html.erb index b4f59f7015,0000000000..36952d69d0 mode 100644,000000..100644 --- a/apps/workbench/app/views/collections/_sharing_button.html.erb +++ b/apps/workbench/app/views/collections/_sharing_button.html.erb @@@ -1,8 -1,0 +1,8 @@@ +<% if @search_sharing.any? %> + <% linktext = "Shared" %> + <% btnstyle = "btn-success" %> +<% else %> + <% linktext = "Share" %> + <% btnstyle = "btn-info" %> +<% end %> - <%= link_to linktext, sharing_popup_collection_url(id: @object.uuid), {class: "btn-xs #{btnstyle}", :remote => true, 'data-toggle' => "modal", 'data-target' => '#collection-sharing-modal-window'} %> ++<%= link_to linktext, sharing_popup_collection_url(id: @object.uuid), {class: "btn #{btnstyle}", :remote => true, 'data-toggle' => "modal", 'data-target' => '#collection-sharing-modal-window'} %> diff --cc apps/workbench/app/views/collections/_sharing_popup.html.erb index 719f8fb4a6,0000000000..f7f0555837 mode 100644,000000..100644 --- a/apps/workbench/app/views/collections/_sharing_popup.html.erb +++ b/apps/workbench/app/views/collections/_sharing_popup.html.erb @@@ -1,37 -1,0 +1,37 @@@ + + diff --cc apps/workbench/app/views/collections/_show_files.html.erb index 28c3396e4f,c5c12792ce..74e02f79fe --- a/apps/workbench/app/views/collections/_show_files.html.erb +++ b/apps/workbench/app/views/collections/_show_files.html.erb @@@ -10,12 -3,8 +3,9 @@@
- - <%= render partial: 'sharing_button' %> - - Collection storage status: + Collection storage status: <%= render partial: 'toggle_persist', locals: { uuid: @object.uuid, current_state: (@is_persistent ? 'persistent' : 'cache') } %> +
@@@ -46,38 -38,31 +39,35 @@@ :class => 'persistent-selection', :friendly_type => "File", :friendly_name => "#{@object.uuid}/#{file_path}", - :href => "#{url_for controller: 'collections', action: 'show', id: @object.uuid }/#{file_path}", - :title => "Click to add this item to your selection list" + :href => url_for(controller: 'collections', action: 'show_file', + uuid: @object.uuid, file: file_path), + :title => "Include #{file_path} in your selections", } %> - - - <%= file[0] %> - - - - <%= link_to (if CollectionsHelper::is_image file[1] - image_tag "#{url_for @object}/#{file_path}", class: "file-list-inline-image" - else - file[1] - end), - {controller: 'collections', action: 'show_file', uuid: @object.uuid, file: file_path, size: file[2], disposition: 'inline'}, - {title: file_path} %> - - - - <%= raw(human_readable_bytes_html(file[2])) %> - - - -
- <%= link_to raw(''), {controller: 'collections', action: 'show_file', uuid: @object.uuid, file: file_path, size: file[2], disposition: 'attachment'}, {class: 'btn btn-info btn-sm', title: 'Download'} %> -
- - - <% end; end %> - - + <%= link_to(raw(''), + link_params.merge(disposition: 'inline'), + {title: "View #{file_path}", class: "btn btn-info btn-sm"}) %> + <%= link_to(raw(''), + link_params.merge(disposition: 'attachment'), + {title: "Download #{file_path}", class: "btn btn-info btn-sm"}) %> + + <% if CollectionsHelper::is_image(filename) %> +
<%= filename %>
+ +
+ <%= link_to(image_tag("#{url_for @object}/#{file_path}"), + link_params.merge(disposition: 'inline'), + {title: file_path}) %> +
+ <% else %> +
<%= filename %>
+ + <% end %> + + <% end # if file or directory %> + <% end # file_tree.each %> + <%= raw(dirstack.map { |_| "" }.join("")) %> + <% end # if file_tree %> + +<% content_for :footer_html do %> + +<% end %> diff --cc apps/workbench/app/views/collections/show.html.erb index 0000000000,9fc67ac4cd..c26b74c65a mode 000000,100644..100644 --- a/apps/workbench/app/views/collections/show.html.erb +++ b/apps/workbench/app/views/collections/show.html.erb @@@ -1,0 -1,105 +1,111 @@@ +
+
+
+
+

+ <% default_name = "Collection #{@object.uuid}" %> + <% name_html = render_editable_attribute @object, 'name', nil, {data: {emptytext: default_name}} %> + <%= (/\S/.match(name_html)) ? name_html : default_name %> +

+
+
+ + <% if not (@output_of.andand.any? or @log_of.andand.any?) %> +

No source information available.

+ <% end %> + + <% if @output_of.andand.any? %> +

Output of jobs:
+ <%= render_arvados_object_list_start(@output_of, 'Show all jobs', + jobs_path(filter: [['output', '=', @object.uuid]].to_json)) do |job| %> + <%= link_to_if_arvados_object(job, friendly_name: true) %>
+ <% end %> +

+ <% end %> + + <% if @log_of.andand.any? %> +

Log of jobs:
+ <%= render_arvados_object_list_start(@log_of, 'Show all jobs', + jobs_path(filter: [['log', '=', @object.uuid]].to_json)) do |job| %> + <%= link_to_if_arvados_object(job, friendly_name: true) %>
+ <% end %> +

+ <% end %> +
+
+
+
+
+
+

+ Activity +

+
+
+ +
+ <% if not @logs.andand.any? %> +

+ Created: <%= @object.created_at.to_s(:long) %> +

+

+ Last modified: <%= @object.modified_at.to_s(:long) %> by <%= link_to_if_arvados_object @object.modified_by_user_uuid, friendly_name: true %> +

+ <% else %> + <%= render_arvados_object_list_start(@logs, 'Show all activity', + logs_path(filters: [['object_uuid','=',@object.uuid]].to_json)) do |log| %> +

+ <%= time_ago_in_words(log.event_at) %> ago: <%= log.summary %> + <% if log.object_uuid %> + <%= link_to_if_arvados_object log.object_uuid, link_text: raw('') %> + <% end %> +

+ <% end %> + <% end %> +
+
+
+
+
+
+

+ Sharing and permissions +

+
+
+ ++ ++
++ <%= render partial: 'sharing_button' %> ++
++ +
+ <% if @folders.andand.any? %> +

Included in folders:
+ <%= render_arvados_object_list_start(@folders, 'Show all folders', + links_path(filter: [['head_uuid', '=', @object.uuid], + ['link_class', '=', 'name']].to_json)) do |folder| %> + <%= link_to_if_arvados_object(folder, friendly_name: true) %>
+ <% end %> +

+ <% end %> + <% if @permissions.andand.any? %> +

Readable by:
+ <%= render_arvados_object_list_start(@permissions, 'Show all permissions', + links_path(filter: [['head_uuid', '=', @object.uuid], + ['link_class', '=', 'permission']].to_json)) do |link| %> + <%= link_to_if_arvados_object(link.tail_uuid, friendly_name: true) %>
+ <% end %> +

+ <% end %> ++ +
+
+
+
+ + <%= render file: 'application/show.html.erb' %> diff --cc apps/workbench/config/routes.rb index 43eb7ae628,c12cc989d7..6e3d66b86b --- a/apps/workbench/config/routes.rb +++ b/apps/workbench/config/routes.rb @@@ -39,13 -40,13 +40,16 @@@ ArvadosWorkbench::Application.routes.dr get 'compare', on: :collection end resources :links - match '/collections/graph' => 'collections#graph' + get '/collections/graph' => 'collections#graph' resources :collections do post 'set_persistent', on: :member + get 'sharing_popup', :on => :member + post 'share', :on => :member + post 'unshare', :on => :member end + get('/collections/download/:uuid/:reader_token/*file' => 'collections#show_file', + format: false) + get '/collections/download/:uuid/:reader_token' => 'collections#show_file_links' get '/collections/:uuid/*file' => 'collections#show_file', :format => false resources :folders do match 'remove/:item_uuid', on: :member, via: :delete, action: :remove_item diff --cc services/api/app/models/arvados_model.rb index 290e156478,bfd228e5e0..adff09d53c --- a/services/api/app/models/arvados_model.rb +++ b/services/api/app/models/arvados_model.rb @@@ -187,26 -187,15 +187,17 @@@ class ArvadosModel < ActiveRecord::Bas def ensure_owner_uuid_is_permitted raise PermissionDeniedError if !current_user - if self.respond_to? :owner_uuid= + if respond_to? :owner_uuid= self.owner_uuid ||= current_user.uuid - if self.owner_uuid_changed? - if current_user.uuid == self.owner_uuid or - current_user.can? write: self.owner_uuid - # current_user is, or has :write permission on, the new owner - else - logger.warn "User #{current_user.uuid} tried to change owner_uuid of #{self.class.to_s} #{self.uuid} to #{self.owner_uuid} but does not have permission to write to #{self.owner_uuid}" - raise PermissionDeniedError - end - end + end + if self.owner_uuid_changed? - if current_user.uuid == self.owner_uuid or + if new_record? + return true - elsif current_user.uuid == self.owner_uuid_was or - current_user.uuid == self.uuid or - current_user.can? write: self.owner_uuid_was - # current user is, or has :write permission on, the previous owner - return true ++ elsif current_user.uuid == self.owner_uuid or + current_user.can? write: self.owner_uuid + # current_user is, or has :write permission on, the new owner else - logger.warn "User #{current_user.uuid} tried to change owner_uuid of #{self.class.to_s} #{self.uuid} to #{self.owner_uuid} but does not have permission to write to #{self.owner_uuid}" + logger.warn "User #{current_user.uuid} tried to modify #{self.class.to_s} #{self.uuid} but does not have permission to write #{self.owner_uuid_was}" raise PermissionDeniedError end end