65 lines
2.1 KiB
Ruby
65 lines
2.1 KiB
Ruby
|
# 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
|