mirror of
https://github.com/discourse/discourse.git
synced 2024-12-02 05:29:17 -06:00
720e1965e3
In the past we used suppress_from_homepage, it had mixed semantics it would remove from category list if category list was on home and unconditionally remove from latest. New setting explicitly only removes from latest list but leaves the category list alond
171 lines
5.4 KiB
Ruby
171 lines
5.4 KiB
Ruby
require_dependency 'pinned_check'
|
|
|
|
class CategoryList
|
|
include ActiveModel::Serialization
|
|
|
|
cattr_accessor :preloaded_topic_custom_fields
|
|
self.preloaded_topic_custom_fields = Set.new
|
|
|
|
attr_accessor :categories,
|
|
:uncategorized,
|
|
:draft,
|
|
:draft_key,
|
|
:draft_sequence
|
|
|
|
def initialize(guardian = nil, options = {})
|
|
@guardian = guardian || Guardian.new
|
|
@options = options
|
|
|
|
find_relevant_topics if options[:include_topics]
|
|
find_categories
|
|
|
|
prune_empty
|
|
find_user_data
|
|
sort_unpinned
|
|
trim_results
|
|
|
|
if preloaded_topic_custom_fields.present?
|
|
displayable_topics = @categories.map(&:displayable_topics)
|
|
displayable_topics.flatten!
|
|
displayable_topics.compact!
|
|
|
|
if displayable_topics.present?
|
|
Topic.preload_custom_fields(
|
|
displayable_topics,
|
|
preloaded_topic_custom_fields
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
def preload_key
|
|
"categories_list".freeze
|
|
end
|
|
|
|
private
|
|
|
|
def find_relevant_topics
|
|
@topics_by_id = {}
|
|
@topics_by_category_id = {}
|
|
|
|
category_featured_topics = CategoryFeaturedTopic.select([:category_id, :topic_id]).order(:rank)
|
|
|
|
@all_topics = Topic.where(id: category_featured_topics.map(&:topic_id))
|
|
@all_topics = @all_topics.includes(:last_poster) if @options[:include_topics]
|
|
@all_topics.each do |t|
|
|
# hint for the serializer
|
|
t.include_last_poster = true if @options[:include_topics]
|
|
@topics_by_id[t.id] = t
|
|
end
|
|
|
|
category_featured_topics.each do |cft|
|
|
@topics_by_category_id[cft.category_id] ||= []
|
|
@topics_by_category_id[cft.category_id] << cft.topic_id
|
|
end
|
|
end
|
|
|
|
def find_categories
|
|
@categories = Category.includes(
|
|
:uploaded_background,
|
|
:uploaded_logo,
|
|
:topic_only_relative_url,
|
|
subcategories: [:topic_only_relative_url]
|
|
).secured(@guardian)
|
|
|
|
@categories = @categories.where("categories.parent_category_id = ?", @options[:parent_category_id].to_i) if @options[:parent_category_id].present?
|
|
|
|
if SiteSetting.fixed_category_positions
|
|
@categories = @categories.order(:position, :id)
|
|
else
|
|
@categories = @categories.order('COALESCE(categories.posts_week, 0) DESC')
|
|
.order('COALESCE(categories.posts_month, 0) DESC')
|
|
.order('COALESCE(categories.posts_year, 0) DESC')
|
|
.order('id ASC')
|
|
end
|
|
|
|
@categories = @categories.to_a
|
|
|
|
category_user = {}
|
|
default_notification_level = nil
|
|
unless @guardian.anonymous?
|
|
category_user = Hash[*CategoryUser.where(user: @guardian.user).pluck(:category_id, :notification_level).flatten]
|
|
default_notification_level = CategoryUser.notification_levels[:regular]
|
|
end
|
|
|
|
allowed_topic_create = Set.new(Category.topic_create_allowed(@guardian).pluck(:id))
|
|
@categories.each do |category|
|
|
category.notification_level = category_user[category.id] || default_notification_level
|
|
category.permission = CategoryGroup.permission_types[:full] if allowed_topic_create.include?(category.id)
|
|
category.has_children = category.subcategories.present?
|
|
end
|
|
|
|
if @options[:parent_category_id].blank?
|
|
subcategories = {}
|
|
to_delete = Set.new
|
|
@categories.each do |c|
|
|
if c.parent_category_id.present?
|
|
subcategories[c.parent_category_id] ||= []
|
|
subcategories[c.parent_category_id] << c.id
|
|
to_delete << c
|
|
end
|
|
end
|
|
@categories.each { |c| c.subcategory_ids = subcategories[c.id] }
|
|
@categories.delete_if { |c| to_delete.include?(c) }
|
|
end
|
|
|
|
if @topics_by_category_id
|
|
@categories.each do |c|
|
|
topics_in_cat = @topics_by_category_id[c.id]
|
|
if topics_in_cat.present?
|
|
c.displayable_topics = []
|
|
topics_in_cat.each do |topic_id|
|
|
topic = @topics_by_id[topic_id]
|
|
if topic.present? && @guardian.can_see?(topic)
|
|
# topic.category is very slow under rails 4.2
|
|
topic.association(:category).target = c
|
|
c.displayable_topics << topic
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def prune_empty
|
|
return if SiteSetting.allow_uncategorized_topics
|
|
@categories.delete_if { |c| c.uncategorized? && c.displayable_topics.blank? }
|
|
end
|
|
|
|
# Attach some data for serialization to each topic
|
|
def find_user_data
|
|
if @guardian.current_user && @all_topics.present?
|
|
topic_lookup = TopicUser.lookup_for(@guardian.current_user, @all_topics)
|
|
@all_topics.each { |ft| ft.user_data = topic_lookup[ft.id] }
|
|
end
|
|
end
|
|
|
|
# Put unpinned topics at the end of the list
|
|
def sort_unpinned
|
|
if @guardian.current_user && @all_topics.present?
|
|
@categories.each do |c|
|
|
next if c.displayable_topics.blank? || c.displayable_topics.size <= c.num_featured_topics
|
|
unpinned = []
|
|
c.displayable_topics.each do |t|
|
|
unpinned << t if t.pinned_at && PinnedCheck.unpinned?(t, t.user_data)
|
|
end
|
|
unless unpinned.empty?
|
|
c.displayable_topics = (c.displayable_topics - unpinned) + unpinned
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def trim_results
|
|
@categories.each do |c|
|
|
next if c.displayable_topics.blank?
|
|
c.displayable_topics = c.displayable_topics[0, c.num_featured_topics]
|
|
end
|
|
end
|
|
|
|
end
|