diff options
Diffstat (limited to 'app/services/topics/merge_service.rb')
-rw-r--r-- | app/services/topics/merge_service.rb | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/app/services/topics/merge_service.rb b/app/services/topics/merge_service.rb new file mode 100644 index 00000000000..0d256579fe0 --- /dev/null +++ b/app/services/topics/merge_service.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +module Topics + class MergeService + attr_accessor :source_topic, :target_topic + + def initialize(source_topic, target_topic) + @source_topic = source_topic + @target_topic = target_topic + end + + def execute + validate_parameters! + + ::Projects::ProjectTopic.transaction do + move_project_topics + refresh_target_topic_counters + delete_source_topic + end + end + + private + + def validate_parameters! + raise ArgumentError, 'The source topic is not a topic.' unless source_topic.is_a?(Projects::Topic) + raise ArgumentError, 'The target topic is not a topic.' unless target_topic.is_a?(Projects::Topic) + raise ArgumentError, 'The source topic and the target topic are identical.' if source_topic == target_topic + end + + # rubocop: disable CodeReuse/ActiveRecord + def move_project_topics + project_ids_for_projects_currently_using_source_and_target = ::Projects::ProjectTopic + .where(topic_id: target_topic).select(:project_id) + # Only update for projects that exclusively use the source topic + ::Projects::ProjectTopic.where(topic_id: source_topic.id) + .where.not(project_id: project_ids_for_projects_currently_using_source_and_target) + .update_all(topic_id: target_topic.id) + + # Delete source topic for projects that were using source and target + ::Projects::ProjectTopic.where(topic_id: source_topic.id).delete_all + end + + def refresh_target_topic_counters + target_topic.update!( + total_projects_count: total_projects_count(target_topic.id), + non_private_projects_count: non_private_projects_count(target_topic.id) + ) + end + + def delete_source_topic + source_topic.destroy! + end + + def total_projects_count(topic_id) + ::Projects::ProjectTopic.where(topic_id: topic_id).count + end + + def non_private_projects_count(topic_id) + ::Projects::ProjectTopic.joins(:project).where(topic_id: topic_id).where('projects.visibility_level in (10, 20)') + .count + end + # rubocop: enable CodeReuse/ActiveRecord + end +end |