Merge branch '10498-register-with-chosen-api' closes #10498
[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     params = _index_requires_parameters.
5       merge({
6               uuid: {
7                 type: 'string', required: false, default: nil
8               },
9             })
10     params.delete(:select)
11     params
12   end
13
14   def render_404_if_no_object
15     if params[:action] == 'contents'
16       if !params[:uuid]
17         # OK!
18         @object = nil
19         true
20       elsif @object
21         # Project group
22         true
23       elsif (@object = User.where(uuid: params[:uuid]).first)
24         # "Home" pseudo-project
25         true
26       else
27         super
28       end
29     else
30       super
31     end
32   end
33
34   def contents
35     load_searchable_objects
36     send_json({
37       :kind => "arvados#objectList",
38       :etag => "",
39       :self_link => "",
40       :offset => @offset,
41       :limit => @limit,
42       :items_available => @items_available,
43       :items => @objects.as_api_response(nil)
44     })
45   end
46
47   protected
48
49   def load_searchable_objects
50     all_objects = []
51     @items_available = 0
52
53     # Trick apply_where_limit_order_params into applying suitable
54     # per-table values. *_all are the real ones we'll apply to the
55     # aggregate set.
56     limit_all = @limit
57     offset_all = @offset
58     # save the orders from the current request as determined by load_param,
59     # but otherwise discard them because we're going to be getting objects
60     # from many models
61     request_orders = @orders.clone
62     @orders = []
63
64     request_filters = @filters
65
66     klasses = [Group,
67      Job, PipelineInstance, PipelineTemplate, ContainerRequest, Workflow,
68      Collection,
69      Human, Specimen, Trait]
70
71     table_names = klasses.map(&:table_name)
72     request_filters.each do |col, op, val|
73       if col.index('.') && !table_names.include?(col.split('.', 2)[0])
74         raise ArgumentError.new("Invalid attribute '#{col}' in filter")
75       end
76     end
77
78     wanted_klasses = []
79     request_filters.each do |col,op,val|
80       if op == 'is_a'
81         (val.is_a?(Array) ? val : [val]).each do |type|
82           type = type.split('#')[-1]
83           type[0] = type[0].capitalize
84           wanted_klasses << type
85         end
86       end
87     end
88
89     klasses.each do |klass|
90       next if wanted_klasses.any? and !wanted_klasses.include?(klass.to_s)
91
92       # If the currently requested orders specifically match the
93       # table_name for the current klass, apply that order.
94       # Otherwise, order by recency.
95       request_order =
96         request_orders.andand.find { |r| r =~ /^#{klass.table_name}\./i } ||
97         klass.default_orders.join(", ")
98
99       @select = nil
100       where_conds = {}
101       where_conds[:owner_uuid] = @object.uuid if @object
102       if klass == Collection
103         @select = klass.selectable_attributes - ["manifest_text"]
104       elsif klass == Group
105         where_conds[:group_class] = "project"
106       end
107
108       @filters = request_filters.map do |col, op, val|
109         if !col.index('.')
110           [col, op, val]
111         elsif (col = col.split('.', 2))[0] == klass.table_name
112           [col[1], op, val]
113         else
114           nil
115         end
116       end.compact
117
118       @objects = klass.readable_by(*@read_users).
119         order(request_order).where(where_conds)
120       @limit = limit_all - all_objects.count
121       apply_where_limit_order_params klass
122       klass_object_list = object_list
123       klass_items_available = klass_object_list[:items_available] || 0
124       @items_available += klass_items_available
125       @offset = [@offset - klass_items_available, 0].max
126       all_objects += klass_object_list[:items]
127     end
128
129     @objects = all_objects
130     @limit = limit_all
131     @offset = offset_all
132   end
133
134 end