18340: Only trash project groups on delete calls.
[arvados.git] / services / api / test / functional / arvados / v1 / groups_controller_test.rb
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 require 'test_helper'
6
7 class Arvados::V1::GroupsControllerTest < ActionController::TestCase
8
9   test "attempt to delete group without read or write access" do
10     authorize_with :active
11     post :destroy, params: {id: groups(:empty_lonely_group).uuid}
12     assert_response 404
13   end
14
15   test "attempt to delete group without write access" do
16     authorize_with :active
17     post :destroy, params: {id: groups(:all_users).uuid}
18     assert_response 403
19   end
20
21   test "get list of projects" do
22     authorize_with :active
23     get :index, params: {filters: [['group_class', '=', 'project']], format: :json}
24     assert_response :success
25     group_uuids = []
26     json_response['items'].each do |group|
27       assert_equal 'project', group['group_class']
28       group_uuids << group['uuid']
29     end
30     assert_includes group_uuids, groups(:aproject).uuid
31     assert_includes group_uuids, groups(:asubproject).uuid
32     assert_includes group_uuids, groups(:private).uuid
33     assert_not_includes group_uuids, groups(:system_group).uuid
34     assert_not_includes group_uuids, groups(:private_and_can_read_foofile).uuid
35   end
36
37   test "get list of groups that are not projects" do
38     authorize_with :active
39     get :index, params: {filters: [['group_class', '!=', 'project']], format: :json}
40     assert_response :success
41     group_uuids = []
42     json_response['items'].each do |group|
43       assert_not_equal 'project', group['group_class']
44       group_uuids << group['uuid']
45     end
46     assert_not_includes group_uuids, groups(:aproject).uuid
47     assert_not_includes group_uuids, groups(:asubproject).uuid
48   end
49
50   test "get list of groups with bogus group_class" do
51     authorize_with :active
52     get :index, params: {
53       filters: [['group_class', '=', 'nogrouphasthislittleclass']],
54       format: :json,
55     }
56     assert_response :success
57     assert_equal [], json_response['items']
58     assert_equal 0, json_response['items_available']
59   end
60
61   def check_project_contents_response disabled_kinds=[]
62     assert_response :success
63     assert_operator 2, :<=, json_response['items_available']
64     assert_operator 2, :<=, json_response['items'].count
65     kinds = json_response['items'].collect { |i| i['kind'] }.uniq
66     expect_kinds = %w'arvados#group arvados#specimen arvados#pipelineTemplate arvados#job' - disabled_kinds
67     assert_equal expect_kinds, (expect_kinds & kinds)
68
69     json_response['items'].each do |i|
70       if i['kind'] == 'arvados#group'
71         assert(i['group_class'] == 'project',
72                "group#contents returned a non-project group")
73       end
74     end
75
76     disabled_kinds.each do |d|
77       assert_equal true, !kinds.include?(d)
78     end
79   end
80
81   test 'get group-owned objects' do
82     authorize_with :active
83     get :contents, params: {
84       id: groups(:aproject).uuid,
85       format: :json,
86     }
87     check_project_contents_response
88   end
89
90   test "user with project read permission can see project objects" do
91     authorize_with :project_viewer
92     get :contents, params: {
93       id: groups(:aproject).uuid,
94       format: :json,
95     }
96     check_project_contents_response
97   end
98
99   test "list objects across projects" do
100     authorize_with :project_viewer
101     get :contents, params: {
102       format: :json,
103       filters: [['uuid', 'is_a', 'arvados#specimen']]
104     }
105     assert_response :success
106     found_uuids = json_response['items'].collect { |i| i['uuid'] }
107     [[:in_aproject, true],
108      [:in_asubproject, true],
109      [:owned_by_private_group, false]].each do |specimen_fixture, should_find|
110       if should_find
111         assert_includes found_uuids, specimens(specimen_fixture).uuid, "did not find specimen fixture '#{specimen_fixture}'"
112       else
113         refute_includes found_uuids, specimens(specimen_fixture).uuid, "found specimen fixture '#{specimen_fixture}'"
114       end
115     end
116   end
117
118   test "list trashed collections and projects" do
119     authorize_with :active
120     get(:contents, params: {
121           format: :json,
122           include_trash: true,
123           filters: [
124             ['uuid', 'is_a', ['arvados#collection', 'arvados#group']],
125             ['is_trashed', '=', true],
126           ],
127           limit: 10000,
128         })
129     assert_response :success
130     found_uuids = json_response['items'].collect { |i| i['uuid'] }
131     assert_includes found_uuids, groups(:trashed_project).uuid
132     refute_includes found_uuids, groups(:aproject).uuid
133     assert_includes found_uuids, collections(:expired_collection).uuid
134     refute_includes found_uuids, collections(:w_a_z_file).uuid
135   end
136
137   test "list objects in home project" do
138     authorize_with :active
139     get :contents, params: {
140       format: :json,
141       limit: 200,
142       id: users(:active).uuid
143     }
144     assert_response :success
145     found_uuids = json_response['items'].collect { |i| i['uuid'] }
146     assert_includes found_uuids, specimens(:owned_by_active_user).uuid, "specimen did not appear in home project"
147     refute_includes found_uuids, specimens(:in_asubproject).uuid, "specimen appeared unexpectedly in home project"
148   end
149
150   test "list collections in home project" do
151     authorize_with :active
152     get(:contents, params: {
153           format: :json,
154           filters: [
155             ['uuid', 'is_a', 'arvados#collection'],
156           ],
157           limit: 200,
158           id: users(:active).uuid,
159         })
160     assert_response :success
161     found_uuids = json_response['items'].collect { |i| i['uuid'] }
162     assert_includes found_uuids, collections(:collection_owned_by_active).uuid, "collection did not appear in home project"
163     refute_includes found_uuids, collections(:collection_owned_by_active_past_version_1).uuid, "collection appeared unexpectedly in home project"
164   end
165
166   test "list collections in home project, including old versions" do
167     authorize_with :active
168     get(:contents, params: {
169           format: :json,
170           include_old_versions: true,
171           filters: [
172             ['uuid', 'is_a', 'arvados#collection'],
173           ],
174           limit: 200,
175           id: users(:active).uuid,
176         })
177     assert_response :success
178     found_uuids = json_response['items'].collect { |i| i['uuid'] }
179     assert_includes found_uuids, collections(:collection_owned_by_active).uuid, "collection did not appear in home project"
180     assert_includes found_uuids, collections(:collection_owned_by_active_past_version_1).uuid, "old collection version did not appear in home project"
181   end
182
183   test "user with project read permission can see project collections" do
184     authorize_with :project_viewer
185     get :contents, params: {
186       id: groups(:asubproject).uuid,
187       format: :json,
188     }
189     ids = json_response['items'].map { |item| item["uuid"] }
190     assert_includes ids, collections(:baz_file_in_asubproject).uuid
191   end
192
193   [
194     ['collections.name', 'asc', :<=, "name"],
195     ['collections.name', 'desc', :>=, "name"],
196     ['name', 'asc', :<=, "name"],
197     ['name', 'desc', :>=, "name"],
198     ['collections.created_at', 'asc', :<=, "created_at"],
199     ['collections.created_at', 'desc', :>=, "created_at"],
200     ['created_at', 'asc', :<=, "created_at"],
201     ['created_at', 'desc', :>=, "created_at"],
202   ].each do |column, order, operator, field|
203     test "user with project read permission can sort projects on #{column} #{order}" do
204       authorize_with :project_viewer
205       get :contents, params: {
206         id: groups(:asubproject).uuid,
207         format: :json,
208         filters: [['uuid', 'is_a', "arvados#collection"]],
209         order: "#{column} #{order}"
210       }
211       sorted_values = json_response['items'].collect { |item| item[field] }
212       if field == "name"
213         # Here we avoid assuming too much about the database
214         # collation. Both "alice"<"Bob" and "alice">"Bob" can be
215         # correct. Hopefully it _is_ safe to assume that if "a" comes
216         # before "b" in the ascii alphabet, "aX">"bY" is never true for
217         # any strings X and Y.
218         reliably_sortable_names = sorted_values.select do |name|
219           name[0] >= 'a' && name[0] <= 'z'
220         end.uniq do |name|
221           name[0]
222         end
223         # Preserve order of sorted_values. But do not use &=. If
224         # sorted_values has out-of-order duplicates, we want to preserve
225         # them here, so we can detect them and fail the test below.
226         sorted_values.select! do |name|
227           reliably_sortable_names.include? name
228         end
229       end
230       assert_sorted(operator, sorted_values)
231     end
232   end
233
234   def assert_sorted(operator, sorted_items)
235     actually_checked_anything = false
236     previous = nil
237     sorted_items.each do |entry|
238       if !previous.nil?
239         assert_operator(previous, operator, entry,
240                         "Entries sorted incorrectly.")
241         actually_checked_anything = true
242       end
243       previous = entry
244     end
245     assert actually_checked_anything, "Didn't even find two items to compare."
246   end
247
248   # Even though the project_viewer tests go through other controllers,
249   # I'm putting them here so they're easy to find alongside the other
250   # project tests.
251   def check_new_project_link_fails(link_attrs)
252     @controller = Arvados::V1::LinksController.new
253     post :create, params: {
254       link: {
255         link_class: "permission",
256         name: "can_read",
257         head_uuid: groups(:aproject).uuid,
258       }.merge(link_attrs)
259     }
260     assert_includes(403..422, response.status)
261   end
262
263   test "user with project read permission can't add users to it" do
264     authorize_with :project_viewer
265     check_new_project_link_fails(tail_uuid: users(:spectator).uuid)
266   end
267
268   test "user with project read permission can't add items to it" do
269     authorize_with :project_viewer
270     check_new_project_link_fails(tail_uuid: collections(:baz_file).uuid)
271   end
272
273   test "user with project read permission can't rename items in it" do
274     authorize_with :project_viewer
275     @controller = Arvados::V1::LinksController.new
276     post :update, params: {
277       id: jobs(:running).uuid,
278       name: "Denied test name",
279     }
280     assert_includes(403..404, response.status)
281   end
282
283   test "user with project read permission can't remove items from it" do
284     @controller = Arvados::V1::PipelineTemplatesController.new
285     authorize_with :project_viewer
286     post :update, params: {
287       id: pipeline_templates(:two_part).uuid,
288       pipeline_template: {
289         owner_uuid: users(:project_viewer).uuid,
290       }
291     }
292     assert_response 403
293   end
294
295   test "user with project read permission can't delete it" do
296     authorize_with :project_viewer
297     post :destroy, params: {id: groups(:aproject).uuid}
298     assert_response 403
299   end
300
301   test 'get group-owned objects with limit' do
302     authorize_with :active
303     get :contents, params: {
304       id: groups(:aproject).uuid,
305       limit: 1,
306       format: :json,
307     }
308     assert_response :success
309     assert_operator 1, :<, json_response['items_available']
310     assert_equal 1, json_response['items'].count
311   end
312
313   test 'get group-owned objects with limit and offset' do
314     authorize_with :active
315     get :contents, params: {
316       id: groups(:aproject).uuid,
317       limit: 1,
318       offset: 12345,
319       format: :json,
320     }
321     assert_response :success
322     assert_operator 1, :<, json_response['items_available']
323     assert_equal 0, json_response['items'].count
324   end
325
326   test 'get group-owned objects with additional filter matching nothing' do
327     authorize_with :active
328     get :contents, params: {
329       id: groups(:aproject).uuid,
330       filters: [['uuid', 'in', ['foo_not_a_uuid','bar_not_a_uuid']]],
331       format: :json,
332     }
333     assert_response :success
334     assert_equal [], json_response['items']
335     assert_equal 0, json_response['items_available']
336   end
337
338   %w(offset limit).each do |arg|
339     ['foo', '', '1234five', '0x10', '-8'].each do |val|
340       test "Raise error on bogus #{arg} parameter #{val.inspect}" do
341         authorize_with :active
342         get :contents, params: {
343           :id => groups(:aproject).uuid,
344           :format => :json,
345           arg => val,
346         }
347         assert_response 422
348       end
349     end
350   end
351
352   test "Collection contents don't include manifest_text or unsigned_manifest_text" do
353     authorize_with :active
354     get :contents, params: {
355       id: groups(:aproject).uuid,
356       filters: [["uuid", "is_a", "arvados#collection"]],
357       format: :json,
358     }
359     assert_response :success
360     refute(json_response["items"].any? { |c| not c["portable_data_hash"] },
361            "response included an item without a portable data hash")
362     refute(json_response["items"].any? { |c| c.include?("manifest_text") },
363            "response included an item with manifest_text")
364     refute(json_response["items"].any? { |c| c.include?("unsigned_manifest_text") },
365            "response included an item with unsigned_manifest_text")
366   end
367
368   test 'get writable_by list for owned group' do
369     authorize_with :active
370     get :show, params: {
371       id: groups(:aproject).uuid,
372       format: :json
373     }
374     assert_response :success
375     assert_not_nil(json_response['writable_by'],
376                    "Should receive uuid list in 'writable_by' field")
377     assert_includes(json_response['writable_by'], users(:active).uuid,
378                     "owner should be included in writable_by list")
379   end
380
381   test 'no writable_by list for group with read-only access' do
382     authorize_with :rominiadmin
383     get :show, params: {
384       id: groups(:testusergroup_admins).uuid,
385       format: :json
386     }
387     assert_response :success
388     assert_equal([json_response['owner_uuid']],
389                  json_response['writable_by'],
390                  "Should only see owner_uuid in 'writable_by' field")
391   end
392
393   test 'get writable_by list by admin user' do
394     authorize_with :admin
395     get :show, params: {
396       id: groups(:testusergroup_admins).uuid,
397       format: :json
398     }
399     assert_response :success
400     assert_not_nil(json_response['writable_by'],
401                    "Should receive uuid list in 'writable_by' field")
402     assert_includes(json_response['writable_by'],
403                     users(:admin).uuid,
404                     "Current user should be included in 'writable_by' field")
405   end
406
407   test 'creating subproject with duplicate name fails' do
408     authorize_with :active
409     post :create, params: {
410       group: {
411         name: 'A Project',
412         owner_uuid: users(:active).uuid,
413         group_class: 'project',
414       },
415     }
416     assert_response 422
417     response_errors = json_response['errors']
418     assert_not_nil response_errors, 'Expected error in response'
419     assert(response_errors.first.include?('duplicate key'),
420            "Expected 'duplicate key' error in #{response_errors.first}")
421   end
422
423   test 'creating duplicate named subproject succeeds with ensure_unique_name' do
424     authorize_with :active
425     post :create, params: {
426       group: {
427         name: 'A Project',
428         owner_uuid: users(:active).uuid,
429         group_class: 'project',
430       },
431       ensure_unique_name: true
432     }
433     assert_response :success
434     new_project = json_response
435     assert_not_equal(new_project['uuid'],
436                      groups(:aproject).uuid,
437                      "create returned same uuid as existing project")
438     assert_match(/^A Project \(\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z\)$/,
439                  new_project['name'])
440   end
441
442   [
443     [['owner_uuid', '!=', 'zzzzz-tpzed-xurymjxw79nv3jz'], 200,
444         'zzzzz-d1hrv-subprojpipeline', 'zzzzz-d1hrv-1xfj6xkicf2muk2'],
445     [["pipeline_instances.state", "not in", ["Complete", "Failed"]], 200,
446         'zzzzz-d1hrv-1xfj6xkicf2muk2', 'zzzzz-d1hrv-i3e77t9z5y8j9cc'],
447     [['container_requests.requesting_container_uuid', '=', nil], 200,
448         'zzzzz-xvhdp-cr4queuedcontnr', 'zzzzz-xvhdp-cr4requestercn2'],
449     [['container_requests.no_such_column', '=', nil], 422],
450     [['container_requests.', '=', nil], 422],
451     [['.requesting_container_uuid', '=', nil], 422],
452     [['no_such_table.uuid', '!=', 'zzzzz-tpzed-xurymjxw79nv3jz'], 422],
453   ].each do |filter, expect_code, expect_uuid, not_expect_uuid|
454     test "get contents with '#{filter}' filter" do
455       authorize_with :active
456       get :contents, params: {filters: [filter], format: :json}
457       assert_response expect_code
458       if expect_code == 200
459         assert_not_empty json_response['items']
460         item_uuids = json_response['items'].collect {|item| item['uuid']}
461         assert_includes(item_uuids, expect_uuid)
462         assert_not_includes(item_uuids, not_expect_uuid)
463       end
464     end
465   end
466
467   test 'get contents with jobs and pipeline instances disabled' do
468     Rails.configuration.API.DisabledAPIs = ConfigLoader.to_OrderedOptions(
469       {'jobs.index'=>{}, 'pipeline_instances.index'=>{}})
470
471     authorize_with :active
472     get :contents, params: {
473       id: groups(:aproject).uuid,
474       format: :json,
475     }
476     check_project_contents_response %w'arvados#pipelineInstance arvados#job'
477   end
478
479   test 'get contents with low max_index_database_read' do
480     # Some result will certainly have at least 12 bytes in a
481     # restricted column
482     Rails.configuration.API.MaxIndexDatabaseRead = 12
483     authorize_with :active
484     get :contents, params: {
485           id: groups(:aproject).uuid,
486           format: :json,
487         }
488     assert_response :success
489     assert_not_empty(json_response['items'])
490     assert_operator(json_response['items'].count,
491                     :<, json_response['items_available'])
492   end
493
494   test 'get contents, recursive=true' do
495     authorize_with :active
496     params = {
497       id: groups(:aproject).uuid,
498       recursive: true,
499       format: :json,
500     }
501     get :contents, params: params
502     owners = json_response['items'].map do |item|
503       item['owner_uuid']
504     end
505     assert_includes(owners, groups(:aproject).uuid)
506     assert_includes(owners, groups(:asubproject).uuid)
507   end
508
509   [false, nil].each do |recursive|
510     test "get contents, recursive=#{recursive.inspect}" do
511       authorize_with :active
512       params = {
513         id: groups(:aproject).uuid,
514         format: :json,
515       }
516       params[:recursive] = false if recursive == false
517       get :contents, params: params
518       owners = json_response['items'].map do |item|
519         item['owner_uuid']
520       end
521       assert_includes(owners, groups(:aproject).uuid)
522       refute_includes(owners, groups(:asubproject).uuid)
523     end
524   end
525
526   test 'get home project contents, recursive=true' do
527     authorize_with :active
528     get :contents, params: {
529           id: users(:active).uuid,
530           recursive: true,
531           format: :json,
532         }
533     owners = json_response['items'].map do |item|
534       item['owner_uuid']
535     end
536     assert_includes(owners, users(:active).uuid)
537     assert_includes(owners, groups(:aproject).uuid)
538     assert_includes(owners, groups(:asubproject).uuid)
539   end
540
541   [:afiltergroup, :private_role].each do |grp|
542     test "delete non-project group #{grp}" do
543       authorize_with :admin
544       assert_not_nil Group.find_by_uuid(groups(grp).uuid)
545       assert !Group.find_by_uuid(groups(grp).uuid).is_trashed
546       post :destroy, params: {
547             id: groups(grp).uuid,
548             format: :json,
549           }
550       assert_response :success
551       # Should not be trashed
552       assert_nil Group.find_by_uuid(groups(grp).uuid)
553     end
554   end
555
556   ### trashed project tests ###
557
558   #
559   # The structure is
560   #
561   # trashed_project         (zzzzz-j7d0g-trashedproject1)
562   #   trashed_subproject    (zzzzz-j7d0g-trashedproject2)
563   #   trashed_subproject3   (zzzzz-j7d0g-trashedproject3)
564   #   zzzzz-xvhdp-cr5trashedcontr
565
566   [:active,
567    :admin].each do |auth|
568     # project: to query,    to untrash,    is visible, parent contents listing success
569     [
570      [:trashed_project,     [],                 false, true],
571      [:trashed_project,     [:trashed_project], true,  true],
572      [:trashed_subproject,  [],                 false, false],
573      [:trashed_subproject,  [:trashed_project], true,  true],
574      [:trashed_subproject3, [:trashed_project], false, true],
575      [:trashed_subproject3, [:trashed_subproject3], false, false],
576      [:trashed_subproject3, [:trashed_project, :trashed_subproject3], true, true],
577     ].each do |project, untrash, visible, success|
578
579       test "contents listing #{project} #{untrash} as #{auth}" do
580         authorize_with auth
581         untrash.each do |pr|
582           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
583         end
584         get :contents, params: {
585               id: groups(project).owner_uuid,
586               format: :json
587             }
588         if success
589           assert_response :success
590           item_uuids = json_response['items'].map do |item|
591             item['uuid']
592           end
593           if visible
594             assert_includes(item_uuids, groups(project).uuid)
595           else
596             assert_not_includes(item_uuids, groups(project).uuid)
597           end
598         else
599           assert_response 404
600         end
601       end
602
603       test "contents of #{project} #{untrash} as #{auth}" do
604         authorize_with auth
605         untrash.each do |pr|
606           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
607         end
608         get :contents, params: {
609               id: groups(project).uuid,
610               format: :json
611             }
612         if visible
613           assert_response :success
614         else
615           assert_response 404
616         end
617       end
618
619       test "index #{project} #{untrash} as #{auth}" do
620         authorize_with auth
621         untrash.each do |pr|
622           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
623         end
624         get :index, params: {
625               format: :json,
626             }
627         assert_response :success
628         item_uuids = json_response['items'].map do |item|
629           item['uuid']
630         end
631         if visible
632           assert_includes(item_uuids, groups(project).uuid)
633         else
634           assert_not_includes(item_uuids, groups(project).uuid)
635         end
636       end
637
638       test "show #{project} #{untrash} as #{auth}" do
639         authorize_with auth
640         untrash.each do |pr|
641           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
642         end
643         get :show, params: {
644               id: groups(project).uuid,
645               format: :json
646             }
647         if visible
648           assert_response :success
649         else
650           assert_response 404
651         end
652       end
653
654       test "show include_trash=false #{project} #{untrash} as #{auth}" do
655         authorize_with auth
656         untrash.each do |pr|
657           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
658         end
659         get :show, params: {
660               id: groups(project).uuid,
661               format: :json,
662               include_trash: false
663             }
664         if visible
665           assert_response :success
666         else
667           assert_response 404
668         end
669       end
670
671       test "show include_trash #{project} #{untrash} as #{auth}" do
672         authorize_with auth
673         untrash.each do |pr|
674           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
675         end
676         get :show, params: {
677               id: groups(project).uuid,
678               format: :json,
679               include_trash: true
680             }
681         assert_response :success
682       end
683
684       test "index include_trash #{project} #{untrash} as #{auth}" do
685         authorize_with auth
686         untrash.each do |pr|
687           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
688         end
689         get :index, params: {
690               format: :json,
691               include_trash: true
692             }
693         assert_response :success
694         item_uuids = json_response['items'].map do |item|
695           item['uuid']
696         end
697         assert_includes(item_uuids, groups(project).uuid)
698       end
699     end
700
701     test "delete project #{auth}" do
702       authorize_with auth
703       [:trashed_project].each do |pr|
704         Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
705       end
706       assert !Group.find_by_uuid(groups(:trashed_project).uuid).is_trashed
707       post :destroy, params: {
708             id: groups(:trashed_project).uuid,
709             format: :json,
710           }
711       assert_response :success
712       assert Group.find_by_uuid(groups(:trashed_project).uuid).is_trashed
713     end
714
715     test "untrash project #{auth}" do
716       authorize_with auth
717       assert Group.find_by_uuid(groups(:trashed_project).uuid).is_trashed
718       post :untrash, params: {
719             id: groups(:trashed_project).uuid,
720             format: :json,
721           }
722       assert_response :success
723       assert !Group.find_by_uuid(groups(:trashed_project).uuid).is_trashed
724     end
725
726     test "untrash project with name conflict #{auth}" do
727       authorize_with auth
728       [:trashed_project].each do |pr|
729         Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
730       end
731       gc = Group.create!({owner_uuid: "zzzzz-j7d0g-trashedproject1",
732                          name: "trashed subproject 3",
733                          group_class: "project"})
734       post :untrash, params: {
735             id: groups(:trashed_subproject3).uuid,
736             format: :json,
737             ensure_unique_name: true
738            }
739       assert_response :success
740       assert_match /^trashed subproject 3 \(\d{4}-\d\d-\d\d.*?Z\)$/, json_response['name']
741     end
742
743     test "move trashed subproject to new owner #{auth}" do
744       authorize_with auth
745       assert_nil Group.readable_by(users(auth)).where(uuid: groups(:trashed_subproject).uuid).first
746       put :update, params: {
747             id: groups(:trashed_subproject).uuid,
748             group: {
749               owner_uuid: users(:active).uuid
750             },
751             include_trash: true,
752             format: :json,
753           }
754       assert_response :success
755       assert_not_nil Group.readable_by(users(auth)).where(uuid: groups(:trashed_subproject).uuid).first
756     end
757   end
758
759   test 'get shared owned by another user' do
760     authorize_with :user_bar_in_sharing_group
761
762     act_as_system_user do
763       Link.create!(
764         tail_uuid: users(:user_bar_in_sharing_group).uuid,
765         link_class: 'permission',
766         name: 'can_read',
767         head_uuid: groups(:project_owned_by_foo).uuid)
768     end
769
770     get :shared, params: {:filters => [["group_class", "=", "project"]], :include => "owner_uuid"}
771
772     assert_equal 1, json_response['items'].length
773     assert_equal json_response['items'][0]["uuid"], groups(:project_owned_by_foo).uuid
774
775     assert_equal 1, json_response['included'].length
776     assert_equal json_response['included'][0]["uuid"], users(:user_foo_in_sharing_group).uuid
777   end
778
779   test 'get shared, owned by unreadable project' do
780     authorize_with :user_bar_in_sharing_group
781
782     act_as_system_user do
783       Group.find_by_uuid(groups(:project_owned_by_foo).uuid).update!(owner_uuid: groups(:aproject).uuid)
784       Link.create!(
785         tail_uuid: users(:user_bar_in_sharing_group).uuid,
786         link_class: 'permission',
787         name: 'can_read',
788         head_uuid: groups(:project_owned_by_foo).uuid)
789     end
790
791     get :shared, params: {:filters => [["group_class", "=", "project"]], :include => "owner_uuid"}
792
793     assert_equal 1, json_response['items'].length
794     assert_equal json_response['items'][0]["uuid"], groups(:project_owned_by_foo).uuid
795
796     assert_equal 0, json_response['included'].length
797   end
798
799   test 'get shared, add permission link' do
800     authorize_with :user_bar_in_sharing_group
801
802     act_as_system_user do
803       Link.create!(tail_uuid: groups(:group_for_sharing_tests).uuid,
804                    head_uuid: groups(:project_owned_by_foo).uuid,
805                    link_class: 'permission',
806                    name: 'can_manage')
807     end
808
809     get :shared, params: {:filters => [["group_class", "=", "project"]], :include => "owner_uuid"}
810
811     assert_equal 1, json_response['items'].length
812     assert_equal groups(:project_owned_by_foo).uuid, json_response['items'][0]["uuid"]
813
814     assert_equal 1, json_response['included'].length
815     assert_equal users(:user_foo_in_sharing_group).uuid, json_response['included'][0]["uuid"]
816   end
817
818   ### contents with exclude_home_project
819
820   test 'contents, exclude home owned by another user' do
821     authorize_with :user_bar_in_sharing_group
822
823     act_as_system_user do
824       Link.create!(
825         tail_uuid: users(:user_bar_in_sharing_group).uuid,
826         link_class: 'permission',
827         name: 'can_read',
828         head_uuid: groups(:project_owned_by_foo).uuid)
829       Link.create!(
830         tail_uuid: users(:user_bar_in_sharing_group).uuid,
831         link_class: 'permission',
832         name: 'can_read',
833         head_uuid: collections(:collection_owned_by_foo).uuid)
834     end
835
836     get :contents, params: {:include => "owner_uuid", :exclude_home_project => true}
837
838     assert_equal 2, json_response['items'].length
839     assert_equal json_response['items'][0]["uuid"], groups(:project_owned_by_foo).uuid
840     assert_equal json_response['items'][1]["uuid"], collections(:collection_owned_by_foo).uuid
841
842     assert_equal 1, json_response['included'].length
843     assert_equal json_response['included'][0]["uuid"], users(:user_foo_in_sharing_group).uuid
844   end
845
846   test 'contents, exclude home, owned by unreadable project' do
847     authorize_with :user_bar_in_sharing_group
848
849     act_as_system_user do
850       Group.find_by_uuid(groups(:project_owned_by_foo).uuid).update!(owner_uuid: groups(:aproject).uuid)
851       Link.create!(
852         tail_uuid: users(:user_bar_in_sharing_group).uuid,
853         link_class: 'permission',
854         name: 'can_read',
855         head_uuid: groups(:project_owned_by_foo).uuid)
856     end
857
858     get :contents, params: {:include => "owner_uuid", :exclude_home_project => true}
859
860     assert_equal 1, json_response['items'].length
861     assert_equal json_response['items'][0]["uuid"], groups(:project_owned_by_foo).uuid
862
863     assert_equal 0, json_response['included'].length
864   end
865
866   test 'contents, exclude home, add permission link' do
867     authorize_with :user_bar_in_sharing_group
868
869     act_as_system_user do
870       Link.create!(tail_uuid: groups(:group_for_sharing_tests).uuid,
871                    head_uuid: groups(:project_owned_by_foo).uuid,
872                    link_class: 'permission',
873                    name: 'can_manage')
874     end
875
876     get :contents, params: {:include => "owner_uuid", :exclude_home_project => true}
877
878     assert_equal 1, json_response['items'].length
879     assert_equal groups(:project_owned_by_foo).uuid, json_response['items'][0]["uuid"]
880
881     assert_equal 1, json_response['included'].length
882     assert_equal users(:user_foo_in_sharing_group).uuid, json_response['included'][0]["uuid"]
883   end
884
885   test 'contents, exclude home, with parent specified' do
886     authorize_with :active
887
888     get :contents, params: {id: groups(:aproject).uuid, :include => "owner_uuid", :exclude_home_project => true}
889
890     assert_response 422
891   end
892 end