discourse/app/models/category_featured_topic.rb

102 lines
3.1 KiB
Ruby
Raw Normal View History

2013-02-05 13:16:51 -06:00
class CategoryFeaturedTopic < ActiveRecord::Base
belongs_to :category
belongs_to :topic
NEXT_CATEGORY_ID_KEY = 'category-featured-topic:next-category-id'.freeze
BATCH_SIZE = 100
# Populates the category featured topics.
def self.feature_topics(batched: false)
current = {}
CategoryFeaturedTopic.select(:topic_id, :category_id).order(:rank).each do |f|
(current[f.category_id] ||= []) << f.topic_id
end
next_category_id = batched ? ($redis.get(NEXT_CATEGORY_ID_KEY) || 0) : 0
categories = Category.select(:id, :topic_id, :num_featured_topics)
.where('id >= ?', next_category_id)
.order('id ASC')
.limit(BATCH_SIZE)
if batched
if categories.count == BATCH_SIZE
next_id = Category.where('id > ?', categories.last.id).order('id asc').limit(1).pluck(:id)[0]
next_id ? $redis.setex(NEXT_CATEGORY_ID_KEY, 1.day, next_id) : $redis.del(NEXT_CATEGORY_ID_KEY)
else
$redis.del(NEXT_CATEGORY_ID_KEY)
end
end
categories.find_each do |c|
CategoryFeaturedTopic.feature_topics_for(c, current[c.id] || [])
2013-02-05 13:16:51 -06:00
end
end
2017-07-27 20:20:09 -05:00
def self.feature_topics_for(c, existing = nil)
return if c.blank?
2013-02-07 09:45:24 -06:00
query_opts = {
per_page: c.num_featured_topics,
except_topic_ids: [c.topic_id],
visible: true,
no_definitions: true
}
2017-08-17 14:26:31 -05:00
# It may seem a bit odd that we are running 2 queries here, when admin
# can clearly pull out all the topics needed.
# We do so, so anonymous will ALWAYS get some topics
# If we only fetched as admin we may have a situation where anon can see
# no featured topics (all the previous 2x topics are only visible to admins)
# Add topics, even if they're in secured categories or invisible
query = TopicQuery.new(CategoryFeaturedTopic.fake_admin, query_opts)
results = query.list_category_topic_ids(c).uniq
# Add some topics that are visible to everyone:
2017-07-27 20:20:09 -05:00
anon_query = TopicQuery.new(nil, query_opts.merge(except_topic_ids: [c.topic_id] + results))
results += anon_query.list_category_topic_ids(c).uniq
return if results == existing
2013-02-05 13:16:51 -06:00
CategoryFeaturedTopic.transaction do
CategoryFeaturedTopic.where(category_id: c.id).delete_all
if results
results.each_with_index do |topic_id, idx|
begin
c.category_featured_topics.create(topic_id: topic_id, rank: idx)
rescue PG::UniqueViolation
# If another process features this topic, just ignore it
end
end
end
2013-02-05 13:16:51 -06:00
end
end
def self.fake_admin
# fake an admin
admin = User.new
admin.admin = true
admin.id = -1
admin
end
2013-08-30 12:39:31 -05:00
2013-02-05 13:16:51 -06:00
end
# == Schema Information
#
# Table name: category_featured_topics
#
# category_id :integer not null
# topic_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
2013-06-16 19:48:58 -05:00
# rank :integer default(0), not null
2013-08-13 15:09:27 -05:00
# id :integer not null, primary key
#
# Indexes
#
2013-06-16 19:48:58 -05:00
# cat_featured_threads (category_id,topic_id) UNIQUE
# index_category_featured_topics_on_category_id_and_rank (category_id,rank)
#