20943: Tweak the docs a bit to discuss different trashing behaviors.
[arvados.git] / services / api / app / controllers / sys_controller.rb
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 class SysController < ApplicationController
6   skip_before_action :find_object_by_uuid
7   skip_before_action :render_404_if_no_object
8   before_action :admin_required
9
10   def trash_sweep
11     act_as_system_user do
12       # Sweep trashed collections
13       Collection.
14         where('delete_at is not null and delete_at < statement_timestamp()').
15         in_batches(of: 15).
16         destroy_all
17       Collection.
18         where('is_trashed = false and trash_at < statement_timestamp()').
19         in_batches(of: 15).
20         update_all('is_trashed = true')
21
22       # Want to make sure the #update_trash hook on the Group class
23       # runs.  It does a couple of important things:
24       #
25       # - For projects, puts all the subprojects in the trashed_groups table.
26       #
27       # - For role groups, outbound permissions are deleted.
28       Group.
29         where("is_trashed = false and trash_at < statement_timestamp()").each do |grp|
30         grp.is_trashed = true
31         grp.save
32       end
33
34       # Sweep groups and their contents that are ready to be deleted
35       Group.
36         where('delete_at is not null and delete_at < statement_timestamp()').each do |group|
37           delete_project_and_contents(group.uuid)
38       end
39
40       # Sweep expired tokens
41       ActiveRecord::Base.connection.execute("DELETE from api_client_authorizations where expires_at <= statement_timestamp()")
42     end
43     head :no_content
44   end
45
46   protected
47
48   def delete_project_and_contents(p_uuid)
49     p = Group.find_by_uuid(p_uuid)
50     if !p
51       raise "can't sweep group '#{p_uuid}', it may not exist"
52     end
53     if p.group_class == 'project'
54       # First delete sub projects
55       Group.where({group_class: 'project', owner_uuid: p_uuid}).each do |sub_project|
56         delete_project_and_contents(sub_project.uuid)
57       end
58       # Next, iterate over all tables which have owner_uuid fields, with some
59       # exceptions, and delete records owned by this project
60       skipped_classes = ['Group', 'User']
61       ActiveRecord::Base.descendants.reject(&:abstract_class?).each do |klass|
62         if !skipped_classes.include?(klass.name) && klass.columns.collect(&:name).include?('owner_uuid')
63           klass.where({owner_uuid: p_uuid}).in_batches(of: 15).destroy_all
64         end
65       end
66     end
67     # Finally delete the group itself
68     p.destroy
69   end
70 end