X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/3ef580c47029ff0fbf959b044f29c183f41cb609..e6769d20505e2c8c74b2d7e3f9c2f33f2a2db092:/services/api/lib/can_be_an_owner.rb diff --git a/services/api/lib/can_be_an_owner.rb b/services/api/lib/can_be_an_owner.rb index 75a63509c2..6f30f5ae33 100644 --- a/services/api/lib/can_be_an_owner.rb +++ b/services/api/lib/can_be_an_owner.rb @@ -1,14 +1,24 @@ +# Copyright (C) The Arvados Authors. All rights reserved. +# +# SPDX-License-Identifier: AGPL-3.0 + # Protect referential integrity of owner_uuid columns in other tables # that can refer to the uuid column in this table. module CanBeAnOwner def self.included(base) + base.extend(ClassMethods) + # Rails' "has_many" can prevent us from destroying the owner # record when other objects refer to it. ActiveRecord::Base.connection.tables.each do |t| next if t == base.table_name next if t == 'schema_migrations' + next if t == 'permission_refresh_lock' + next if t == 'ar_internal_metadata' + next if t == 'commit_ancestors' + next if t == 'commits' klass = t.classify.constantize next unless klass and 'owner_uuid'.in?(klass.columns.collect(&:name)) base.has_many(t.to_sym, @@ -22,6 +32,42 @@ module CanBeAnOwner base.validate :restrict_uuid_change_breaking_associations end + module ClassMethods + def install_view(type) + conn = ActiveRecord::Base.connection + transaction do + # Check whether the temporary view has already been created + # during this connection. If not, create it. + conn.exec_query "SAVEPOINT check_#{type}_view" + begin + conn.exec_query("SELECT 1 FROM #{type}_view LIMIT 0") + rescue + conn.exec_query "ROLLBACK TO SAVEPOINT check_#{type}_view" + sql = File.read(Rails.root.join("lib", "create_#{type}_view.sql")) + conn.exec_query(sql) + ensure + conn.exec_query "RELEASE SAVEPOINT check_#{type}_view" + end + end + end + end + + def descendant_project_uuids + self.class.install_view('ancestor') + ActiveRecord::Base.connection. + exec_query('SELECT ancestor_view.uuid + FROM ancestor_view + LEFT JOIN groups ON groups.uuid=ancestor_view.uuid + WHERE ancestor_uuid = $1 AND groups.group_class = $2', + # "name" arg is a query label that appears in logs: + "descendant_project_uuids for #{self.uuid}", + # "binds" arg is an array of [col_id, value] for '$1' vars: + [[nil, self.uuid], [nil, 'project']], + ).rows.map do |project_uuid,| + project_uuid + end + end + protected def restrict_uuid_change_breaking_associations @@ -43,5 +89,4 @@ module CanBeAnOwner self.owner_uuid = uuid end end - end