Merge branch 'master' into 3296-user-profile
[arvados.git] / apps / workbench / app / controllers / projects_controller.rb
index f73b6c074cd14d75b6d8c4d0071a291b1d298532..2b605d3f834feb4e5deb425598a3b16522f2094f 100644 (file)
@@ -8,7 +8,11 @@ class ProjectsController < ApplicationController
   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,73 +52,83 @@ 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
+    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 find_objects_for_index
+    @objects = all_projects
+    super
   end
 
   def show
+    if !@object
+      return render_not_found("object not found")
+    end
     @objects = @object.contents(limit: 50,
                                 include_linked: true,
+                                filters: params[:filters],
                                 offset: params[:offset] || 0)
-    @share_links = Link.filter([['head_uuid', '=', @object.uuid],
-                                ['link_class', '=', 'permission']])
     @logs = Log.limit(10).filter([['object_uuid', '=', @object.uuid]])
+    @users = User.limit(10000).
+      select(["uuid", "is_active", "first_name", "last_name"]).
+      filter([['is_active', '=', 'true']])
+    @groups = Group.limit(10000).
+      select(["uuid", "name", "description"])
 
-    @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]
-        end
-      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
+    begin
+      @share_links = Link.permissions_for(@object)
+      @user_is_manager = true
+    rescue ArvadosApiClient::AccessForbiddenException,
+           ArvadosApiClient::NotFoundException
+      @share_links = []
+      @user_is_manager = false
     end
+
+    @objects_and_names = get_objects_and_names @objects
+
     if params[:partial]
       respond_to do |f|
         f.json {
@@ -126,7 +140,7 @@ class ProjectsController < ApplicationController
                                         project: @object
                                       }),
             next_page_href: (next_page_offset and
-                             url_for(offset: next_page_offset, partial: true))
+                             url_for(offset: next_page_offset, filters: params[:filters], partial: true))
           }
         }
       end
@@ -145,4 +159,59 @@ class ProjectsController < ApplicationController
     @updates = params['project']
     super
   end
+
+  helper_method :get_objects_and_names
+  def get_objects_and_names(objects)
+    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]
+        end
+      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