0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-08 13:25:19 +08:00
discourse/app/services/nested_topic/convert_category.rb
Mark VanLandingham 2409dc314a
FEATURE: Add nested replies category conversion (#41236)
At the moment there is no way in the UI to convert a category to nested
replies. This introduces a backfill button and UI to show admin the
current state (using category custom field). Screenshots pretty much
tell the story:

<img width="1483" height="1187" alt="Screenshot 2026-07-02 at 10 08
23 AM"
src="https://github.com/user-attachments/assets/532bd7d2-8aae-455a-9744-aee0f3ac5b82"
/>
<img width="1498" height="1247" alt="Screenshot 2026-07-02 at 10 08
38 AM"
src="https://github.com/user-attachments/assets/a1382732-8b72-4526-a770-72b6452b56bb"
/>
<img width="1460" height="1220" alt="Screenshot 2026-07-02 at 10 08
58 AM"
src="https://github.com/user-attachments/assets/b4113347-c760-4f66-b947-988c270750a6"
/>
2026-07-06 08:22:22 -05:00

94 lines
2.3 KiB
Ruby
Vendored

# frozen_string_literal: true
class NestedTopic::ConvertCategory
include Service::Base
BATCH_SIZE = 1000
params do
attribute :category_id, :integer
validates :category_id, presence: true
end
model :category
policy :nested_replies_enabled
policy :can_edit_category
policy :category_nested_replies_enabled
step :enable_nested_view_for_existing_topics
step :mark_conversion_completed
only_if(:converted_topics?) { step :enqueue_nested_reply_stats_backfill }
private
def fetch_category(params:)
Category.find_by(id: params.category_id)
end
def nested_replies_enabled
SiteSetting.nested_replies_enabled
end
def can_edit_category(guardian:, category:)
guardian.can_edit?(category)
end
def category_nested_replies_enabled(category:)
category.nested_replies_default
end
def enable_nested_view_for_existing_topics(category:)
converted_topic_count = 0
loop do
converted_batch_count = convert_topic_batch(category.id)
break if converted_batch_count.zero?
converted_topic_count += converted_batch_count
end
context[:converted_topic_count] = converted_topic_count
end
def convert_topic_batch(category_id)
DB
.query_single(<<~SQL, category_id:, archetype: Archetype.default, batch_size: BATCH_SIZE)
WITH topics_to_convert AS (
SELECT t.id
FROM topics t
WHERE t.category_id = :category_id
AND t.archetype = :archetype
AND t.deleted_at IS NULL
AND NOT EXISTS (
SELECT 1
FROM nested_topics nt
WHERE nt.topic_id = t.id
)
ORDER BY t.id
LIMIT :batch_size
), inserted AS (
INSERT INTO nested_topics (topic_id, created_at, updated_at)
SELECT id, NOW(), NOW()
FROM topics_to_convert
ON CONFLICT (topic_id) DO NOTHING
RETURNING 1
)
SELECT COUNT(*)
FROM inserted
SQL
.first
.to_i
end
def mark_conversion_completed(category:)
category.mark_nested_replies_conversion_completed!
end
def converted_topics?(converted_topic_count:)
converted_topic_count.positive?
end
def enqueue_nested_reply_stats_backfill(category:)
Jobs.enqueue(:backfill_nested_reply_stats, category_id: category.id)
end
end