13146: Add "include" parameter and rename return field to "included"
[arvados.git] / services / api / app / controllers / arvados / v1 / groups_controller.rb
index 8e195ff990ac6c9fc80f09e5336703781c020e80..18a58c71f99712b8f9d4624eea6106d45b0a146b 100644 (file)
@@ -7,6 +7,9 @@ require "trashable"
 class Arvados::V1::GroupsController < ApplicationController
   include TrashableController
 
+  skip_before_filter :find_object_by_uuid, only: :shared
+  skip_before_filter :render_404_if_no_object, only: :shared
+
   def self._index_requires_parameters
     (super rescue {}).
       merge({
@@ -63,6 +66,58 @@ class Arvados::V1::GroupsController < ApplicationController
     })
   end
 
+  def shared
+    # The purpose of this endpoint is to return the toplevel set of
+    # groups which are *not* reachable through a direct ownership
+    # chain of projects starting from the current user account.  In
+    # other words, groups which to which access was granted via a
+    # permission link or chain of links.
+    #
+    # This also returns (in the "includes" field) the objects that own
+    # those projects (users or non-project groups).
+    #
+    # select groups that are readable by current user AND
+    #   the owner_uuid is a user (but not the current user) OR
+    #   the owner_uuid is not readable by the current user
+    #   the owner_uuid is a group but group_class is not a project
+    #
+    # The intended use of this endpoint is to support clients which
+    # wish to browse those projects which are visible to the user but
+    # are not part of the "home" project.
+
+    load_limit_offset_order_params
+    load_filters_param
+
+    read_parent_check = if current_user.is_admin
+                          ""
+                        else
+                          "NOT EXISTS(SELECT 1 FROM #{PERMISSION_VIEW} WHERE "+
+                            "user_uuid=(:user_uuid) AND target_uuid=groups.owner_uuid AND perm_level >= 1) OR "
+                        end
+
+    @objects = Group.readable_by(*@read_users).where("groups.owner_uuid IN (SELECT users.uuid FROM users WHERE users.uuid != (:user_uuid)) OR "+
+                                                     read_parent_check+
+                                                     "EXISTS(SELECT 1 FROM groups as gp where gp.uuid=groups.owner_uuid and gp.group_class != 'project')",
+                                            user_uuid: current_user.uuid)
+    apply_where_limit_order_params
+
+    owners = @objects.map(&:owner_uuid).to_a
+
+    if params["include"] == "owner_uuid"
+      @extra_included = []
+      @extra_included += Group.readable_by(*@read_users).where(uuid: owners).to_a
+      @extra_included += User.readable_by(*@read_users).where(uuid: owners).to_a
+    end
+
+    index
+  end
+
+  def self._shared_requires_parameters
+    rp = self._index_requires_parameters
+    rp[:include] = { type: 'string', required: false }
+    rp
+  end
+
   protected
 
   def load_searchable_objects
@@ -163,12 +218,7 @@ class Arvados::V1::GroupsController < ApplicationController
         end
       end.compact
 
-      query_on = if klass == Collection and params[:include_trash]
-                   klass.unscoped
-                 else
-                   klass
-                 end
-      @objects = query_on.readable_by(*@read_users, {:include_trash => params[:include_trash]}).
+      @objects = klass.readable_by(*@read_users, {:include_trash => params[:include_trash]}).
                  order(request_order).where(where_conds)
 
       klass_limit = limit_all - all_objects.count