X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/a959f21c8147f26362df392bc3fd3290db69de85..97e3a42d5041515e4c135220b1836805e76a2d94:/apps/workbench/app/controllers/projects_controller.rb diff --git a/apps/workbench/app/controllers/projects_controller.rb b/apps/workbench/app/controllers/projects_controller.rb index f73b6c074c..6287793f76 100644 --- a/apps/workbench/app/controllers/projects_controller.rb +++ b/apps/workbench/app/controllers/projects_controller.rb @@ -3,12 +3,41 @@ class ProjectsController < ApplicationController Group end + def find_object_by_uuid + if current_user and params[:uuid] == current_user.uuid + @object = current_user.dup + @object.uuid = current_user.uuid + class << @object + def name + 'Home' + end + def description + '' + end + def attribute_editable? attr, *args + case attr + when 'description', 'name' + false + else + super + end + end + end + else + super + end + end + def index_pane_list %w(Projects) end def show_pane_list - %w(Contents Permissions Advanced) + if @user_is_manager + %w(Data_collections Jobs_and_pipelines Pipeline_templates Subprojects Other_objects Sharing Advanced) + else + %w(Data_collections Jobs_and_pipelines Pipeline_templates Subprojects Other_objects Advanced) + end end def remove_item @@ -48,89 +77,137 @@ class ProjectsController < ApplicationController end end - def find_objects_for_index - @objects = Group. - filter([['group_class','in',['project','folder']]]). - order('name') - super - parent_of = {current_user.uuid => 'me'} - @objects.each do |ob| - parent_of[ob.uuid] = ob.owner_uuid - end - children_of = {false => [], 'me' => [current_user]} - @objects.each do |ob| - if ob.owner_uuid != current_user.uuid and - not parent_of.has_key? ob.owner_uuid - parent_of[ob.uuid] = false + def move_items + target_uuid = params['target'] + uuids_to_add = session[:selected_move_items] + + 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 |dst| + if resource_class == Collection + dst = Link.new(owner_uuid: target_uuid, + tail_uuid: target_uuid, + head_uuid: dst.uuid, + link_class: 'name', + name: target_uuid) + else + dst.owner_uuid = target_uuid + dst.tail_uuid = target_uuid if dst.class == Link + end + dst.save! end - children_of[parent_of[ob.uuid]] ||= [] - children_of[parent_of[ob.uuid]] << ob end - buildtree = lambda do |children_of, root_uuid=false| - tree = {} - children_of[root_uuid].andand.each do |ob| - tree[ob] = buildtree.call(children_of, ob.uuid) + session[:selected_move_items] = nil + redirect_to @object + end + + def destroy + while (objects = Link.filter([['owner_uuid','=',@object.uuid], + ['tail_uuid','=',@object.uuid]])).any? + objects.each do |object| + object.destroy end - tree - end - sorted_paths = lambda do |tree, depth=0| - paths = [] - tree.keys.sort_by { |ob| - ob.is_a?(String) ? ob : ob.friendly_link_name - }.each do |ob| - paths << {object: ob, depth: depth} - paths += sorted_paths.call tree[ob], depth+1 + end + while (objects = @object.contents(include_linked: false)).any? + objects.each do |object| + object.update_attributes! owner_uuid: current_user.uuid end - paths end - @my_project_tree = - sorted_paths.call buildtree.call(children_of, 'me') - @shared_project_tree = - sorted_paths.call({'Shared with me' => - buildtree.call(children_of, false)}) + if ArvadosBase::resource_class_for_uuid(@object.owner_uuid) == Group + params[:return_to] ||= group_path(@object.owner_uuid) + else + params[:return_to] ||= projects_path + end + super end - def show - @objects = @object.contents(limit: 50, - include_linked: true, - offset: params[:offset] || 0) - @share_links = Link.filter([['head_uuid', '=', @object.uuid], - ['link_class', '=', 'permission']]) - @logs = Log.limit(10).filter([['object_uuid', '=', @object.uuid]]) - - @objects_and_names = [] - @objects.each do |object| - if !(name_links = @objects.links_for(object, 'name')).empty? - name_links.each do |name_link| - @objects_and_names << [object, name_link] + def find_objects_for_index + @objects = all_projects + super + end + + def load_contents_objects kinds=[] + kind_filters = @filters.select do |attr,op,val| + op == 'is_a' and val.is_a? Array and val.count > 1 + end + if /^created_at\b/ =~ @order[0] and kind_filters.count == 1 + # If filtering on multiple types and sorting by date: Get the + # first page of each type, sort the entire set, truncate to one + # page, and use the last item on this page as a filter for + # retrieving the next page. Ideally the API would do this for + # us, but it doesn't (yet). + nextpage_operator = /\bdesc$/i =~ @order[0] ? '<' : '>' + @objects = [] + @name_link_for = {} + kind_filters.each do |attr,op,val| + (val.is_a?(Array) ? val : [val]).each do |type| + objects = @object.contents(order: @order, + limit: @limit, + include_linked: true, + filters: (@filters - kind_filters + [['uuid', 'is_a', type]]), + offset: @offset) + objects.each do |object| + @name_link_for[object.andand.uuid] = objects.links_for(object, 'name').first + end + @objects += objects end - elsif object.respond_to? :name - @objects_and_names << [object, object] + end + @objects = @objects.to_a.sort_by(&:created_at) + @objects.reverse! if nextpage_operator == '<' + @objects = @objects[0..@limit-1] + @next_page_filters = @filters.reject do |attr,op,val| + attr == 'created_at' and op == nextpage_operator + end + if @objects.any? + @next_page_filters += [['created_at', + nextpage_operator, + @objects.last.created_at]] + @next_page_href = url_for(partial: :contents_rows, + filters: @next_page_filters.to_json) else - @objects_and_names << [object, - Link.new(owner_uuid: @object.uuid, - tail_uuid: @object.uuid, - head_uuid: object.uuid, - link_class: "name", - name: "")] + @next_page_href = nil end + else + @objects = @object.contents(order: @order, + limit: @limit, + include_linked: true, + filters: @filters, + offset: @offset) + @next_page_href = next_page_href(partial: :contents_rows) end + end + + def show + if !@object + return render_not_found("object not found") + end + + @user_is_manager = false + @share_links = [] + if @object.uuid != current_user.uuid + begin + @share_links = Link.permissions_for(@object) + @user_is_manager = true + rescue ArvadosApiClient::AccessForbiddenException, + ArvadosApiClient::NotFoundException + end + end + if params[:partial] + load_contents_objects respond_to do |f| f.json { render json: { content: render_to_string(partial: 'show_contents_rows.html', - formats: [:html], - locals: { - objects_and_names: @objects_and_names, - project: @object - }), - next_page_href: (next_page_offset and - url_for(offset: next_page_offset, partial: true)) + formats: [:html]), + next_page_href: @next_page_href } } end else + @objects = [] super end end @@ -145,4 +222,63 @@ class ProjectsController < ApplicationController @updates = params['project'] super end + + helper_method :get_objects_and_names + def get_objects_and_names(objects=nil) + objects = @objects if objects.nil? + objects_and_names = [] + objects.each do |object| + if objects.respond_to? :links_for and + !(name_links = objects.links_for(object, 'name')).empty? + name_links.each do |name_link| + objects_and_names << [object, name_link] + end + elsif @name_link_for.andand[object.uuid] + objects_and_names << [object, @name_link_for[object.uuid]] + elsif object.respond_to? :name + objects_and_names << [object, object] + else + objects_and_names << [object, + Link.new(owner_uuid: @object.uuid, + tail_uuid: @object.uuid, + head_uuid: object.uuid, + link_class: "name", + name: "")] + end + end + objects_and_names + end + + def share_with + if not params[:uuids].andand.any? + @errors = ["No user/group UUIDs specified to share with."] + return render_error(status: 422) + end + results = {"success" => [], "errors" => []} + params[:uuids].each do |shared_uuid| + begin + Link.create(tail_uuid: shared_uuid, link_class: "permission", + name: "can_read", head_uuid: @object.uuid) + rescue ArvadosApiClient::ApiError => error + error_list = error.api_response.andand[:errors] + if error_list.andand.any? + results["errors"] += error_list.map { |e| "#{shared_uuid}: #{e}" } + else + error_code = error.api_status || "Bad status" + results["errors"] << "#{shared_uuid}: #{error_code} response" + end + else + results["success"] << shared_uuid + end + end + if results["errors"].empty? + results.delete("errors") + status = 200 + else + status = 422 + end + respond_to do |f| + f.json { render(json: results, status: status) } + end + end end