diff --git a/app/assets/javascripts/discourse/app/models/topic-list.js b/app/assets/javascripts/discourse/app/models/topic-list.js index bb56578ce17..93ca8a55f9d 100644 --- a/app/assets/javascripts/discourse/app/models/topic-list.js +++ b/app/assets/javascripts/discourse/app/models/topic-list.js @@ -5,6 +5,7 @@ import { isEmpty } from "@ember/utils"; import { Promise } from "rsvp"; import { ajax } from "discourse/lib/ajax"; import RestModel from "discourse/models/rest"; +import Site from "discourse/models/site"; import User from "discourse/models/user"; import deprecated from "discourse-common/lib/deprecated"; import { getOwnerWithFallback } from "discourse-common/lib/get-owner"; @@ -168,6 +169,12 @@ TopicList.reopenClass({ const users = extractByKey(result.users, User); const groups = extractByKey(result.primary_groups, EmberObject); + if (result.topic_list.categories) { + result.topic_list.categories.forEach((c) => { + Site.current().updateCategory(c); + }); + } + return result.topic_list[listKey].map((t) => { t.posters.forEach((p) => { p.user = users[p.user_id]; diff --git a/app/models/topic_list.rb b/app/models/topic_list.rb index de50712dc79..4e021e87369 100644 --- a/app/models/topic_list.rb +++ b/app/models/topic_list.rb @@ -76,6 +76,10 @@ class TopicList @topics ||= load_topics end + def categories + @categories ||= topics.map { |t| [t.category, t.category.parent_category] }.uniq.flatten.compact + end + def load_topics @topics = @topics_input @@ -128,7 +132,12 @@ class TopicList ft.topic_list = self end - topic_preloader_associations = [:image_upload, { topic_thumbnails: :optimized_image }] + topic_preloader_associations = [ + :image_upload, + { topic_thumbnails: :optimized_image }, + { category: :parent_category }, + ] + topic_preloader_associations.concat(DiscoursePluginRegistry.topic_preloader_associations.to_a) ActiveRecord::Associations::Preloader.new( diff --git a/app/serializers/topic_category_serializer.rb b/app/serializers/topic_category_serializer.rb new file mode 100644 index 00000000000..e2961eb84c2 --- /dev/null +++ b/app/serializers/topic_category_serializer.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +class TopicCategorySerializer < ApplicationSerializer + attributes :id, + :name, + :color, + :text_color, + :slug, + :description_text, + :read_restricted, + :parent_category_id + + def include_parent_category_id? + parent_category_id + end + + def name + if object.uncategorized? + I18n.t("uncategorized_category_name", locale: SiteSetting.default_locale) + else + object.name + end + end + + def description_text + if object.uncategorized? + I18n.t("category.uncategorized_description", locale: SiteSetting.default_locale) + else + object.description_text + end + end +end diff --git a/app/serializers/topic_list_serializer.rb b/app/serializers/topic_list_serializer.rb index 5e78f344a3e..814118877d9 100644 --- a/app/serializers/topic_list_serializer.rb +++ b/app/serializers/topic_list_serializer.rb @@ -12,6 +12,7 @@ class TopicListSerializer < ApplicationSerializer has_many :topics, serializer: TopicListItemSerializer, embed: :objects has_many :shared_drafts, serializer: TopicListItemSerializer, embed: :objects has_many :tags, serializer: TagSerializer, embed: :objects + has_many :categories, serializer: TopicCategorySerializer, embed: :objects def can_create_topic scope.can_create?(Topic) @@ -36,4 +37,8 @@ class TopicListSerializer < ApplicationSerializer def include_tags? SiteSetting.tagging_enabled && object.tags.present? end + + def include_categories? + SiteSetting.lazy_load_categories + end end diff --git a/config/site_settings.yml b/config/site_settings.yml index 307624f556a..bab5c11bae8 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -2174,6 +2174,9 @@ developer: instrument_gc_stat_per_request: default: false hidden: true + lazy_load_categories: + default: false + hidden: true navigation: navigation_menu: diff --git a/spec/requests/list_controller_spec.rb b/spec/requests/list_controller_spec.rb index dae18310b1c..0590c26a648 100644 --- a/spec/requests/list_controller_spec.rb +++ b/spec/requests/list_controller_spec.rb @@ -223,6 +223,38 @@ RSpec.describe ListController do expect(response.body).not_to include(restricted_tag.name) end end + + context "with lazy_load_categories" do + fab!(:category) { Fabricate(:category) } + fab!(:subcategory) { Fabricate(:category, parent_category: category) } + + before { topic.update!(category: subcategory) } + + it "returns categories and parent categories if true" do + SiteSetting.lazy_load_categories = true + + get "/latest.json" + + expect(response.status).to eq(200) + expect(response.parsed_body["topic_list"]["topics"].length).to eq(1) + expect(response.parsed_body["topic_list"]["topics"][0]["id"]).to eq(topic.id) + expect(response.parsed_body["topic_list"]["categories"].length).to eq(2) + expect( + response.parsed_body["topic_list"]["categories"].map { |c| c["id"] }, + ).to contain_exactly(category.id, subcategory.id) + end + + it "does not return categories if not true" do + SiteSetting.lazy_load_categories = false + + get "/latest.json" + + expect(response.status).to eq(200) + expect(response.parsed_body["topic_list"]["topics"].length).to eq(1) + expect(response.parsed_body["topic_list"]["topics"][0]["id"]).to eq(topic.id) + expect(response.parsed_body["topic_list"]["categories"]).to eq(nil) + end + end end describe "categories and X" do