Merge branch '3627-selectable-projects' closes #3627
[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 returns name links, which are obsolete, so
10               # remove it when clients have been migrated.
11               include_linked: {
12                 type: 'boolean', required: false, default: false
13               },
14             })
15   end
16
17   def render_404_if_no_object
18     if params[:action] == 'contents'
19       if !params[:uuid]
20         # OK!
21         @object = nil
22         true
23       elsif @object
24         # Project group
25         true
26       elsif (@object = User.where(uuid: params[:uuid]).first)
27         # "Home" pseudo-project
28         true
29       else
30         super
31       end
32     else
33       super
34     end
35   end
36
37   def contents
38     # Set @objects:
39     # include_linked returns name links, which are obsolete, so
40     # remove it when clients have been migrated.
41     load_searchable_objects(owner_uuid: @object.andand.uuid,
42                             include_linked: params[:include_linked])
43     sql = 'link_class=? and head_uuid in (?)'
44     sql_params = ['name', @objects.collect(&:uuid)]
45     if @object
46       sql += ' and tail_uuid=?'
47       sql_params << @object.uuid
48     end
49     @links = Link.where sql, *sql_params
50     @object_list = {
51       :kind  => "arvados#objectList",
52       :etag => "",
53       :self_link => "",
54       :links => @links.as_api_response(nil),
55       :offset => @offset,
56       :limit => @limit,
57       :items_available => @items_available,
58       :items => @objects.as_api_response(nil)
59     }
60     render json: @object_list
61   end
62
63   protected
64
65   def load_searchable_objects opts
66     all_objects = []
67     @items_available = 0
68
69     # Trick apply_where_limit_order_params into applying suitable
70     # per-table values. *_all are the real ones we'll apply to the
71     # aggregate set.
72     limit_all = @limit
73     offset_all = @offset
74     @orders = []
75
76     [Group,
77      Job, PipelineInstance, PipelineTemplate,
78      Collection,
79      Human, Specimen, Trait].each do |klass|
80       @objects = klass.readable_by(*@read_users)
81       if klass == Group
82         @objects = @objects.where(group_class: 'project')
83       end
84       if opts[:owner_uuid]
85         conds = []
86         cond_params = []
87         conds << "#{klass.table_name}.owner_uuid = ?"
88         cond_params << opts[:owner_uuid]
89         if conds.any?
90           cond_sql = '(' + conds.join(') OR (') + ')'
91           @objects = @objects.where(cond_sql, *cond_params)
92         end
93       end
94
95       @objects = @objects.order("#{klass.table_name}.uuid")
96       @limit = limit_all - all_objects.count
97       apply_where_limit_order_params klass
98       klass_items_available = @objects.
99         except(:limit).except(:offset).
100         count(:id, distinct: true)
101       @items_available += klass_items_available
102       @offset = [@offset - klass_items_available, 0].max
103
104       all_objects += @objects.to_a
105     end
106
107     @objects = all_objects
108     @limit = limit_all
109     @offset = offset_all
110   end
111
112 end