Merge branch 'master' into 3219-further-docker-improvements
[arvados.git] / services / api / app / controllers / arvados / v1 / groups_controller.rb
1 class Arvados::V1::GroupsController < ApplicationController
2
3   def self._contents_requires_parameters
4     _index_requires_parameters.
5       merge({
6               uuid: {
7                 type: 'string', required: false, default: nil
8               },
9               include_linked: {
10                 type: 'boolean', required: false, default: false
11               },
12             })
13   end
14
15   def render_404_if_no_object
16     if params[:action] == 'contents' and !params[:uuid]
17       # OK!
18       @object = nil
19     else
20       super
21     end
22   end
23
24   def contents
25     # Set @objects:
26     load_searchable_objects(owner_uuid: @object.andand.uuid, include_linked: params[:include_linked])
27
28     sql = 'link_class=? and head_uuid in (?)'
29     sql_params = ['name', @objects.collect(&:uuid)]
30     if @object
31       sql += ' and tail_uuid=?'
32       sql_params << @object.uuid
33     end
34     @links = Link.where sql, *sql_params
35     @object_list = {
36       :kind  => "arvados#objectList",
37       :etag => "",
38       :self_link => "",
39       :links => @links.as_api_response(nil),
40       :offset => @offset,
41       :limit => @limit,
42       :items_available => @items_available,
43       :items => @objects.as_api_response(nil)
44     }
45     render json: @object_list
46   end
47
48   protected
49
50   def load_searchable_objects opts
51     all_objects = []
52     @items_available = 0
53
54     # Trick apply_where_limit_order_params into applying suitable
55     # per-table values. *_all are the real ones we'll apply to the
56     # aggregate set.
57     limit_all = @limit
58     offset_all = @offset
59     @orders = []
60
61     [Group,
62      Job, PipelineInstance, PipelineTemplate,
63      Collection,
64      Human, Specimen, Trait].each do |klass|
65       @objects = klass.readable_by(*@read_users)
66       if klass == Group
67         @objects = @objects.where('group_class = ?', 'project')
68       end
69       conds = []
70       cond_params = []
71       if opts[:owner_uuid]
72         conds << "#{klass.table_name}.owner_uuid = ?"
73         cond_params << opts[:owner_uuid]
74       end
75       if opts[:include_linked]
76         conds << "#{klass.table_name}.uuid IN (SELECT head_uuid FROM links WHERE link_class=#{klass.sanitize 'name'} AND links.tail_uuid=#{klass.sanitize @object.uuid})"
77       end
78       if conds.any?
79         cond_sql = '(' + conds.join(') OR (') + ')'
80         @objects = @objects.where(cond_sql, *cond_params)
81       end
82       @objects = @objects.order("#{klass.table_name}.uuid")
83       @limit = limit_all - all_objects.count
84       apply_where_limit_order_params
85       klass_items_available = @objects.
86         except(:limit).except(:offset).
87         count(:id, distinct: true)
88       @items_available += klass_items_available
89       @offset = [@offset - klass_items_available, 0].max
90
91       all_objects += @objects.to_a
92     end
93
94     @objects = all_objects
95     @limit = limit_all
96     @offset = offset_all
97   end
98
99 end