# frozen_string_literal: true module Experiments class MoveToProjectService extend Service include Canaid::Helpers::PermissionsHelper attr_reader :errors def initialize(experiment_id:, project_id:, user_id:) @exp = Experiment.find_by(id: experiment_id) @project = Project.find_by(id: project_id) @user = User.find_by(id: user_id) @original_project = @exp&.project @errors = {} end def call return self unless valid? unless can_create_project_experiments?(@user, @project) @errors[:main] = I18n.t('move_to_project_service.project_permission_error') return self end ActiveRecord::Base.transaction do @exp.project = @project @exp.reset_all_users_assignments!(@user) @exp.my_modules.each do |my_module| unless can_move_my_module?(@user, my_module) @errors[:main] = I18n.t('move_to_project_service.my_modules_permission_error') raise end my_module.reset_all_users_assignments!(@user) clean_up_user_my_modules(my_module) end move_activities!(@exp) @exp.save! rescue StandardError if @exp.valid? && @errors.none? @errors[:main] = I18n.t('move_to_project_service.general_error') else @errors.merge!(@exp.errors.to_hash) end raise ActiveRecord::Rollback end track_activity if succeed? self end def succeed? @errors.none? end private def valid? unless @exp && @project && @user @errors[:invalid_arguments] = { 'experiment': @exp, 'project': @project, 'user': @user } .map do |key, value| "Can't find #{key.capitalize}" if value.nil? end.compact return false end if @exp.movable_projects(@user).include?(@project) true else @errors[:target_project_not_valid] = ['Experiment cannot be moved to this project'] end end # recursively move all activities in child associations to new project def move_activities!(subject) Activity.where(subject: subject).find_each do |activity| activity.update!(project: @project) end child_associations = Extends::ACTIVITY_SUBJECT_CHILDREN[subject.class.name.underscore.to_sym] return unless child_associations child_associations.each do |child_association| [subject.public_send(child_association)].flatten.each do |child_subject| next unless child_subject move_activities!(child_subject) end end end def clean_up_user_my_modules(my_module) my_module.user_my_modules.where.not(user_id: @project.users.select(:id)).destroy_all end def track_activity Activities::CreateActivityService .call(activity_type: :move_experiment, owner: @user, team: @project.team, project: @project, subject: @exp, message_items: { experiment: @exp.id, project_new: @project.id, project_original: @original_project.id }) end end end