Fix protocol team assignment propagation [SCI-12199]

This commit is contained in:
Martin Artnik 2025-08-05 14:26:14 +02:00
parent abcc1bfb44
commit 85d78f357a
6 changed files with 33 additions and 27 deletions

View file

@ -35,12 +35,7 @@ module Api
@user_assignment.update!(user_assignment_params.merge(assigned: :manually)) @user_assignment.update!(user_assignment_params.merge(assigned: :manually))
UserAssignments::PropagateAssignmentJob.perform_later( UserAssignments::PropagateAssignmentJob.perform_later(@user_assignment)
@experiment,
@user_assignment.user_id,
@user_assignment.user_role,
current_user.id
)
log_change_activity log_change_activity

View file

@ -110,10 +110,7 @@ module Api
def propagate_job(user_assignment, destroy: false) def propagate_job(user_assignment, destroy: false)
UserAssignments::PropagateAssignmentJob.perform_later( UserAssignments::PropagateAssignmentJob.perform_later(
@project, user_assignment,
user_assignment.user.id,
user_assignment.user_role,
current_user.id,
destroy: destroy destroy: destroy
) )
end end

View file

@ -28,12 +28,7 @@ module UserAssignments
next unless project.experiments.any? next unless project.experiments.any?
# make sure all related experiments and my modules are assigned # make sure all related experiments and my modules are assigned
UserAssignments::PropagateAssignmentJob.perform_later( UserAssignments::PropagateAssignmentJob.perform_later(user_assignment)
project,
user.id,
project.default_public_user_role || UserRole.find_predefined_viewer_role,
@assigned_by&.id
)
end end
end end
end end

View file

@ -113,6 +113,11 @@ module Assignable
# Will be called when an assignment is changed (save/destroy) for the assignable model. # Will be called when an assignment is changed (save/destroy) for the assignable model.
end end
def after_team_assignment_changed(team_assignment = nil)
# Optional, redefine in the assignable model.
# Will be called when an assignment is changed (save/destroy) for the assignable model.
end
def create_user_assignments!(user = created_by) def create_user_assignments!(user = created_by)
# First create initial assignments for the object's creator # First create initial assignments for the object's creator
if top_level_assignable? if top_level_assignable?

View file

@ -601,11 +601,11 @@ class Protocol < ApplicationRecord
end end
parent_protocol.user_assignments.each do |parent_user_assignment| parent_protocol.user_assignments.each do |parent_user_assignment|
parent_protocol.sync_child_protocol_user_assignment(parent_user_assignment, draft.id) parent_protocol.sync_child_protocol_assignment(parent_user_assignment, draft.id)
end end
parent_protocol.user_group_assignments.each do |parent_user_group_assignment| parent_protocol.user_group_assignments.each do |parent_user_group_assignment|
parent_protocol.sync_child_protocol_user_assignment(parent_user_group_assignment, draft.id) parent_protocol.sync_child_protocol_assignment(parent_user_group_assignment, draft.id)
end end
draft draft
end end
@ -678,29 +678,30 @@ class Protocol < ApplicationRecord
published_versions.or(Protocol.where(id: draft&.id)) published_versions.or(Protocol.where(id: draft&.id))
end end
def sync_child_protocol_user_assignment(user_assignment, child_protocol_id = nil) def sync_child_protocol_assignment(assignment, child_protocol_id = nil)
# Copy user assignments to child protocol(s) # Copy user assignments to child protocol(s)
Protocol.transaction(requires_new: true) do Protocol.transaction(requires_new: true) do
# Reload to ensure a potential new draft is also included in child versions # Reload to ensure a potential new draft is also included in child versions
reload reload
assignment_type = user_assignment.respond_to?(:user_group) ? 'user_group' : 'user' assignment_key = assignment.model_name.param_key
assignment_key = "#{assignment_type}_id".to_sym assignable_id_key = assignment_key.gsub('assignment', 'id')
( (
# all or single child version protocol # all or single child version protocol
child_protocol_id ? child_version_protocols.where(id: child_protocol_id) : child_version_protocols child_protocol_id ? child_version_protocols.where(id: child_protocol_id) : child_version_protocols
).find_each do |child_protocol| ).find_each do |child_protocol|
child_assignment = child_protocol.public_send("#{assignment_type}_assignments").find_or_initialize_by( child_assignment = child_protocol.public_send(assignment_key.pluralize).find_or_initialize_by(
assignment_key => user_assignment.public_send(assignment_key) assignable_id_key => assignment.public_send(assignable_id_key)
) )
if user_assignment.destroyed? if assignment.destroyed?
child_assignment.destroy! if child_assignment.persisted? child_assignment.destroy! if child_assignment.persisted?
next next
end end
child_assignment.update!( child_assignment.update!(
user_assignment.attributes.slice( assignment.attributes.slice(
'user_role_id', 'user_role_id',
'assigned', 'assigned',
'assigned_by_id', 'assigned_by_id',
@ -716,13 +717,19 @@ class Protocol < ApplicationRecord
def after_user_assignment_changed(user_assignment) def after_user_assignment_changed(user_assignment)
return unless in_repository_published_original? return unless in_repository_published_original?
sync_child_protocol_user_assignment(user_assignment) sync_child_protocol_assignment(user_assignment)
end end
def after_user_group_assignment_changed(user_group_assignment) def after_user_group_assignment_changed(user_group_assignment)
return unless in_repository_published_original? return unless in_repository_published_original?
sync_child_protocol_user_assignment(user_group_assignment) sync_child_protocol_assignment(user_group_assignment)
end
def after_team_assignment_changed(user_group_assignment)
return unless in_repository_published_original?
sync_child_protocol_assignment(user_group_assignment)
end end
def deep_clone(clone, current_user, include_file_versions: false) def deep_clone(clone, current_user, include_file_versions: false)

View file

@ -14,4 +14,11 @@ class TeamAssignment < ApplicationRecord
scope :as_viewers, -> { where(user_role: UserRole.find_predefined_viewer_role) } scope :as_viewers, -> { where(user_role: UserRole.find_predefined_viewer_role) }
validates :team, uniqueness: { scope: :assignable } validates :team, uniqueness: { scope: :assignable }
after_destroy :call_team_assignment_changed_hook
after_save :call_team_assignment_changed_hook
def call_team_assignment_changed_hook
assignable.__send__(:after_team_assignment_changed, self)
end
end end