mirror of
https://github.com/discourse/discourse.git
synced 2025-05-01 09:14:34 +08:00

This creates two methods in the Category model. This moves the model logic to the model and just calls the Category class methods in ListController. This also adds tests for the two methods created in the Category model. The motivation for this refactor is the code climate score of the this class and readability of the code. Please enter the commit message for your changes. Lines starting
298 lines
9.2 KiB
Ruby
298 lines
9.2 KiB
Ruby
class ListController < ApplicationController
|
|
|
|
skip_before_filter :check_xhr
|
|
|
|
@@categories = [
|
|
# filtered topics lists
|
|
Discourse.filters.map { |f| "category_#{f}".to_sym },
|
|
Discourse.filters.map { |f| "category_none_#{f}".to_sym },
|
|
Discourse.filters.map { |f| "parent_category_category_#{f}".to_sym },
|
|
Discourse.filters.map { |f| "parent_category_category_none_#{f}".to_sym },
|
|
# top summaries
|
|
:category_top,
|
|
:category_none_top,
|
|
:parent_category_category_top,
|
|
# top pages (ie. with a period)
|
|
TopTopic.periods.map { |p| "category_top_#{p}".to_sym },
|
|
TopTopic.periods.map { |p| "category_none_top_#{p}".to_sym },
|
|
TopTopic.periods.map { |p| "parent_category_category_top_#{p}".to_sym },
|
|
# category feeds
|
|
:category_feed,
|
|
].flatten
|
|
|
|
before_filter :set_category, only: @@categories
|
|
|
|
before_filter :ensure_logged_in, except: [
|
|
:topics_by,
|
|
# anonymous filters
|
|
Discourse.anonymous_filters,
|
|
Discourse.anonymous_filters.map { |f| "#{f}_feed".to_sym },
|
|
# categories
|
|
@@categories,
|
|
# top
|
|
:top,
|
|
TopTopic.periods.map { |p| "top_#{p}".to_sym }
|
|
].flatten
|
|
|
|
# Create our filters
|
|
Discourse.filters.each do |filter|
|
|
define_method(filter) do |options = nil|
|
|
list_opts = build_topic_list_options
|
|
list_opts.merge!(options) if options
|
|
user = list_target_user
|
|
list = TopicQuery.new(user, list_opts).public_send("list_#{filter}")
|
|
list.more_topics_url = construct_url_with(list_opts)
|
|
if Discourse.anonymous_filters.include?(filter)
|
|
@description = SiteSetting.site_description
|
|
@rss = filter
|
|
end
|
|
respond(list)
|
|
end
|
|
|
|
define_method("category_#{filter}") do
|
|
self.send(filter, { category: @category.id })
|
|
end
|
|
|
|
define_method("category_none_#{filter}") do
|
|
self.send(filter, { category: @category.id, no_subcategories: true })
|
|
end
|
|
|
|
define_method("parent_category_category_#{filter}") do
|
|
self.send(filter, { category: @category.id })
|
|
end
|
|
|
|
define_method("parent_category_category_none_#{filter}") do
|
|
self.send(filter, { category: @category.id })
|
|
end
|
|
end
|
|
|
|
Discourse.anonymous_filters.each do |filter|
|
|
define_method("#{filter}_feed") do
|
|
discourse_expires_in 1.minute
|
|
|
|
@title = "#{filter.capitalize} Topics"
|
|
@link = "#{Discourse.base_url}/#{filter}"
|
|
@description = I18n.t("rss_description.#{filter}")
|
|
@atom_link = "#{Discourse.base_url}/#{filter}.rss"
|
|
@topic_list = TopicQuery.new.public_send("list_#{filter}")
|
|
|
|
render 'list', formats: [:rss]
|
|
end
|
|
end
|
|
|
|
[:topics_by, :private_messages, :private_messages_sent, :private_messages_unread].each do |action|
|
|
define_method("#{action}") do
|
|
list_opts = build_topic_list_options
|
|
target_user = fetch_user_from_params
|
|
guardian.ensure_can_see_private_messages!(target_user.id) unless action == :topics_by
|
|
list = generate_list_for(action.to_s, target_user, list_opts)
|
|
url_prefix = "topics" unless action == :topics_by
|
|
url = construct_url_with(list_opts, url_prefix)
|
|
list.more_topics_url = url_for(url)
|
|
respond(list)
|
|
end
|
|
end
|
|
|
|
def category_feed
|
|
guardian.ensure_can_see!(@category)
|
|
discourse_expires_in 1.minute
|
|
|
|
@title = @category.name
|
|
@link = "#{Discourse.base_url}/category/#{@category.slug}"
|
|
@description = "#{I18n.t('topics_in_category', category: @category.name)} #{@category.description}"
|
|
@atom_link = "#{Discourse.base_url}/category/#{@category.slug}.rss"
|
|
@topic_list = TopicQuery.new.list_new_in_category(@category)
|
|
|
|
render 'list', formats: [:rss]
|
|
end
|
|
|
|
def popular_redirect
|
|
# We've renamed popular to latest. Use a redirect until we're sure we can
|
|
# safely remove this.
|
|
redirect_to latest_path, :status => 301
|
|
end
|
|
|
|
def top(options = nil)
|
|
discourse_expires_in 1.minute
|
|
|
|
top_options = build_topic_list_options
|
|
top_options.merge!(options) if options
|
|
|
|
top = generate_top_lists(top_options)
|
|
|
|
top.draft_key = Draft::NEW_TOPIC
|
|
top.draft_sequence = DraftSequence.current(current_user, Draft::NEW_TOPIC)
|
|
top.draft = Draft.get(current_user, top.draft_key, top.draft_sequence) if current_user
|
|
|
|
respond_to do |format|
|
|
format.html do
|
|
@top = top
|
|
store_preloaded('top_lists', MultiJson.dump(TopListSerializer.new(top, scope: guardian, root: false)))
|
|
render 'top'
|
|
end
|
|
format.json do
|
|
render json: MultiJson.dump(TopListSerializer.new(top, scope: guardian, root: false))
|
|
end
|
|
end
|
|
end
|
|
|
|
def category_top
|
|
options = { category: @category.id }
|
|
top(options)
|
|
end
|
|
|
|
def category_none_top
|
|
options = { category: @category.id, no_subcategories: true }
|
|
top(options)
|
|
end
|
|
|
|
def parent_category_category_top
|
|
options = { category: @category.id }
|
|
top(options)
|
|
end
|
|
|
|
TopTopic.periods.each do |period|
|
|
define_method("top_#{period}") do |options = nil|
|
|
top_options = build_topic_list_options
|
|
top_options.merge!(options) if options
|
|
top_options[:per_page] = SiteSetting.topics_per_period_in_top_page
|
|
user = list_target_user
|
|
list = TopicQuery.new(user, top_options).public_send("list_top_#{period}")
|
|
list.more_topics_url = construct_url_with(top_options)
|
|
respond(list)
|
|
end
|
|
|
|
define_method("category_top_#{period}") do
|
|
self.send("top_#{period}", { category: @category.id })
|
|
end
|
|
|
|
define_method("category_none_top_#{period}") do
|
|
self.send("top_#{period}", { category: @category.id, no_subcategories: true })
|
|
end
|
|
|
|
define_method("parent_category_category_#{period}") do
|
|
self.send("top_#{period}", { category: @category.id })
|
|
end
|
|
end
|
|
|
|
protected
|
|
|
|
def respond(list)
|
|
discourse_expires_in 1.minute
|
|
|
|
list.draft_key = Draft::NEW_TOPIC
|
|
list.draft_sequence = DraftSequence.current(current_user, Draft::NEW_TOPIC)
|
|
list.draft = Draft.get(current_user, list.draft_key, list.draft_sequence) if current_user
|
|
|
|
respond_to do |format|
|
|
format.html do
|
|
@list = list
|
|
store_preloaded('topic_list', MultiJson.dump(TopicListSerializer.new(list, scope: guardian)))
|
|
render 'list'
|
|
end
|
|
format.json do
|
|
render_serialized(list, TopicListSerializer)
|
|
end
|
|
end
|
|
end
|
|
|
|
def next_page_params(opts = nil)
|
|
opts ||= {}
|
|
route_params = { format: 'json', page: params[:page].to_i + 1 }
|
|
route_params[:category] = @category.slug if @category
|
|
route_params[:parent_category] = @category.parent_category.slug if @category && @category.parent_category
|
|
route_params[:sort_order] = opts[:sort_order] if opts[:sort_order].present?
|
|
route_params[:sort_descending] = opts[:sort_descending] if opts[:sort_descending].present?
|
|
route_params
|
|
end
|
|
|
|
private
|
|
|
|
def set_category
|
|
slug_or_id = params.fetch(:category)
|
|
parent_slug_or_id = params[:parent_category]
|
|
|
|
parent_category_id = nil
|
|
if parent_slug_or_id.present?
|
|
parent_category_id = Category.query_parent_category(parent_slug_or_id)
|
|
raise Discourse::NotFound.new if parent_category_id.blank?
|
|
end
|
|
|
|
@category = Category.query_category(slug_or_id, parent_category_id)
|
|
|
|
guardian.ensure_can_see!(@category)
|
|
|
|
raise Discourse::NotFound.new if @category.blank?
|
|
end
|
|
|
|
def build_topic_list_options
|
|
# exclude_category = 1. from params / 2. parsed from top menu / 3. nil
|
|
options = {
|
|
page: params[:page],
|
|
topic_ids: param_to_integer_list(:topic_ids),
|
|
exclude_category: (params[:exclude_category] || select_menu_item.try(:filter)),
|
|
category: params[:category],
|
|
sort_order: params[:sort_order],
|
|
sort_descending: params[:sort_descending],
|
|
status: params[:status]
|
|
}
|
|
options[:no_subcategories] = true if params[:no_subcategories] == 'true'
|
|
|
|
options
|
|
end
|
|
|
|
def select_menu_item
|
|
menu_item = SiteSetting.top_menu_items.select do |mu|
|
|
(mu.has_specific_category? && mu.specific_category == @category.try(:slug)) ||
|
|
action_name == mu.name ||
|
|
(action_name.include?("top") && mu.name == "top")
|
|
end.first
|
|
|
|
menu_item = nil if menu_item.try(:has_specific_category?) && menu_item.specific_category == @category.try(:slug)
|
|
menu_item
|
|
end
|
|
|
|
def list_target_user
|
|
if params[:user_id] && guardian.is_staff?
|
|
User.find(params[:user_id].to_i)
|
|
else
|
|
current_user
|
|
end
|
|
end
|
|
|
|
def generate_list_for(action, target_user, opts)
|
|
TopicQuery.new(current_user, opts).send("list_#{action}", target_user)
|
|
end
|
|
|
|
def construct_url_with(opts, url_prefix = nil)
|
|
method = url_prefix.blank? ? "#{action_name}_path" : "#{url_prefix}_#{action_name}_path"
|
|
public_send(method, opts.merge(next_page_params(opts)))
|
|
end
|
|
|
|
def generate_top_lists(options)
|
|
top = TopLists.new
|
|
|
|
options[:per_page] = SiteSetting.topics_per_period_in_top_summary
|
|
topic_query = TopicQuery.new(current_user, options)
|
|
|
|
if current_user.present?
|
|
periods = [best_period_for(current_user.previous_visit_at)]
|
|
else
|
|
periods = TopTopic.periods
|
|
end
|
|
|
|
periods.each { |period| top.send("#{period}=", topic_query.list_top_for(period)) }
|
|
|
|
top
|
|
end
|
|
|
|
def best_period_for(date)
|
|
date ||= 1.year.ago
|
|
return :yearly if date < 180.days.ago
|
|
return :monthly if date < 35.days.ago
|
|
return :weekly if date < 8.days.ago
|
|
:daily
|
|
end
|
|
|
|
end
|