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