diff --git a/app/models/team.rb b/app/models/team.rb index ded06872c..ad6707741 100644 --- a/app/models/team.rb +++ b/app/models/team.rb @@ -49,7 +49,20 @@ class Team < ApplicationRecord has_many :activities, inverse_of: :team, dependent: :destroy has_many :assets, inverse_of: :team, dependent: :destroy has_many :team_repositories, inverse_of: :team, dependent: :destroy - has_many :shared_repositories, through: :team_repositories, source: :repository + has_many :repository_sharing_user_assignments, + (lambda do |team| + joins( + "INNER JOIN repositories "\ + "ON user_assignments.assignable_type = 'RepositoryBase' "\ + "AND user_assignments.assignable_id = repositories.id" + ).where(team_id: team.id) + .where.not('user_assignments.team_id = repositories.team_id') + end), + class_name: 'UserAssignment' + has_many :shared_repositories, + through: :repository_sharing_user_assignments, + source: :assignable, + source_type: 'RepositoryBase' attr_accessor :without_templates diff --git a/app/models/user_assignment.rb b/app/models/user_assignment.rb index 2e31bfd89..408281436 100644 --- a/app/models/user_assignment.rb +++ b/app/models/user_assignment.rb @@ -2,6 +2,8 @@ class UserAssignment < ApplicationRecord before_validation -> { self.team ||= (assignable.is_a?(Team) ? assignable : assignable.team) } + after_create :assign_shared_inventories, if: -> { assignable.is_a?(Team) } + before_destroy :unassign_shared_inventories, if: -> { assignable.is_a?(Team) } belongs_to :assignable, polymorphic: true, touch: true belongs_to :user_role @@ -12,4 +14,20 @@ class UserAssignment < ApplicationRecord enum assigned: { automatically: 0, manually: 1 }, _suffix: true validates :user, uniqueness: { scope: %i(assignable team_id) } + + private + + def assign_shared_inventories + assignable.repository_sharing_user_assignments + .select('DISTINCT assignable_id, user_assignments.*') + .find_each do |repository_sharing_user_assignment| + new_user_assignment = repository_sharing_user_assignment.dup + new_user_assignment.assign_attributes(user: user) + new_user_assignment.save! + end + end + + def unassign_shared_inventories + assignable.repository_sharing_user_assignments.where(user: user).find_each(&:destroy!) + end end diff --git a/db/migrate/20220624091046_migrate_shared_repositories_to_user_assignments.rb b/db/migrate/20220624091046_migrate_shared_repositories_to_user_assignments.rb new file mode 100644 index 000000000..f1783cb45 --- /dev/null +++ b/db/migrate/20220624091046_migrate_shared_repositories_to_user_assignments.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +class MigrateSharedRepositoriesToUserAssignments < ActiveRecord::Migration[6.1] + def up + viewer_role = UserRole.find_by(name: UserRole.public_send('viewer_role').name) + normal_user_role = UserRole.find_by(name: UserRole.public_send('normal_user_role').name) + + TeamRepository.where(permission_level: %i(shared_read shared_write)) + .preload(:team, :repository) + .find_each do |team_repository| + user_role = if team_repository.shared_read? + viewer_role + elsif team_repository.shared_write? + normal_user_role + end + + team_repository.team.users.find_in_batches(batch_size: 100) do |users_batch| + user_assignments = [] + users_batch.each do |user| + user_assignments << UserAssignment.new(user: user, assignable: team_repository.repository, + user_role: user_role, team: team_repository.team) + end + UserAssignment.import(user_assignments) + end + end + end + + def down + UserAssignment.joins("INNER JOIN repositories ON user_assignments.assignable_id = repositories.id "\ + "AND user_assignments.assignable_type = 'RepositoryBase' "\ + "AND user_assignments.team_id != repositories.team_id") + .delete_all + end +end