discourse/app/controllers/list_controller.rb

353 lines
11 KiB
Ruby
Raw Normal View History

2013-02-05 14:16:51 -05:00
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
2014-01-13 19:02:14 -05:00
before_filter :ensure_logged_in, except: [
:topics_by,
# anonymous filters
Discourse.anonymous_filters,
Discourse.anonymous_filters.map { |f| "#{f}_feed".to_sym },
# anonymous categorized filters
Discourse.anonymous_filters.map { |f| "category_#{f}".to_sym },
Discourse.anonymous_filters.map { |f| "category_none_#{f}".to_sym },
Discourse.anonymous_filters.map { |f| "parent_category_category_#{f}".to_sym },
Discourse.anonymous_filters.map { |f| "parent_category_category_none_#{f}".to_sym },
# category feeds
:category_feed,
# top summaries
:top,
:category_top,
:category_none_top,
:parent_category_category_top,
# top pages (ie. with a period)
TopTopic.periods.map { |p| "top_#{p}".to_sym },
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 },
2014-01-13 19:02:14 -05:00
].flatten
2013-02-05 14:16:51 -05:00
# Create our filters
2013-12-23 18:50:36 -05:00
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
if filter == :latest && params[:category].blank?
list_opts[:no_definitions] = true
end
list = TopicQuery.new(user, list_opts).public_send("list_#{filter}")
2014-02-25 12:15:20 -05:00
list.more_topics_url = construct_next_url_with(list_opts)
list.prev_topics_url = construct_prev_url_with(list_opts)
2013-12-23 18:50:36 -05:00
if Discourse.anonymous_filters.include?(filter)
2013-10-11 12:35:12 -04:00
@description = SiteSetting.site_description
@rss = filter
end
2013-02-05 14:16:51 -05:00
respond(list)
2013-02-07 10:45:24 -05:00
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
2013-02-05 14:16:51 -05:00
end
2013-12-23 18:50:36 -05:00
Discourse.anonymous_filters.each do |filter|
2013-07-05 16:49:06 -04:00
define_method("#{filter}_feed") do
discourse_expires_in 1.minute
@title = "#{SiteSetting.title} - #{I18n.t("rss_description.#{filter}")}"
@link = "#{Discourse.base_url}/#{filter}"
@description = I18n.t("rss_description.#{filter}")
@atom_link = "#{Discourse.base_url}/#{filter}.rss"
@topic_list = TopicQuery.new(nil, order: 'activity').public_send("list_#{filter}")
2013-12-23 18:50:36 -05:00
render 'list', formats: [:rss]
2013-07-05 16:49:06 -04:00
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
2014-02-25 12:15:20 -05:00
list.more_topics_url = url_for(construct_next_url_with(list_opts, url_prefix))
list.prev_topics_url = url_for(construct_prev_url_with(list_opts, url_prefix))
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_for_url}"
@description = "#{I18n.t('topics_in_category', category: @category.name)} #{@category.description}"
@atom_link = "#{Discourse.base_url}/category/#{@category.slug_for_url}.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)
2014-01-13 19:02:14 -05:00
discourse_expires_in 1.minute
top_options = build_topic_list_options
top_options.merge!(options) if options
top = generate_top_lists(top_options)
2013-12-23 18:50:36 -05:00
2014-02-06 05:39:43 -05:00
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
2013-12-23 18:50:36 -05:00
respond_to do |format|
format.html do
@top = top
2014-01-13 19:02:14 -05:00
store_preloaded('top_lists', MultiJson.dump(TopListSerializer.new(top, scope: guardian, root: false)))
2013-12-23 18:50:36 -05:00
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
2014-01-13 19:02:14 -05:00
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
2014-01-13 19:02:14 -05:00
user = list_target_user
list = TopicQuery.new(user, top_options).list_top_for(period)
2014-02-25 12:15:20 -05:00
list.more_topics_url = construct_next_url_with(top_options)
list.prev_topics_url = construct_prev_url_with(top_options)
2014-01-13 19:02:14 -05:00
respond(list)
end
define_method("category_top_#{period}") do
self.send("top_#{period}", { category: @category.id })
end
2013-02-05 14:16:51 -05:00
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
2013-12-13 17:18:28 -05:00
end
protected
2013-02-05 14:16:51 -05:00
def respond(list)
2013-12-23 18:50:36 -05:00
discourse_expires_in 1.minute
2013-02-05 14:16:51 -05:00
list.draft_key = Draft::NEW_TOPIC
list.draft_sequence = DraftSequence.current(current_user, Draft::NEW_TOPIC)
2013-12-26 18:35:53 -05:00
list.draft = Draft.get(current_user, list.draft_key, list.draft_sequence) if current_user
2013-02-07 10:45:24 -05:00
2013-02-05 14:16:51 -05:00
respond_to do |format|
format.html do
2013-02-07 10:45:24 -05:00
@list = list
2013-02-05 14:16:51 -05:00
store_preloaded('topic_list', MultiJson.dump(TopicListSerializer.new(list, scope: guardian)))
render 'list'
end
format.json do
render_serialized(list, TopicListSerializer)
end
end
end
2013-02-07 10:45:24 -05:00
def next_page_params(opts = nil)
2014-02-25 12:15:20 -05:00
page_params(opts).merge(page: params[:page].to_i + 1)
end
def prev_page_params(opts = nil)
2014-03-03 12:56:37 -05:00
pg = params[:page].to_i
if pg > 1
page_params(opts).merge(page: pg - 1)
else
page_params(opts).merge(page: nil)
end
2014-02-25 12:15:20 -05:00
end
private
def page_params(opts = nil)
opts ||= {}
2014-02-25 12:15:20 -05:00
route_params = {format: 'json'}
route_params[:category] = @category.slug_for_url if @category
route_params[:parent_category] = @category.parent_category.slug_for_url if @category && @category.parent_category
route_params[:order] = opts[:order] if opts[:order].present?
route_params[:ascending] = opts[:ascending] if opts[:ascending].present?
route_params
2013-02-05 14:16:51 -05:00
end
def set_category
slug_or_id = params.fetch(:category)
parent_slug_or_id = params[:parent_category]
2013-10-23 14:40:39 -04:00
parent_category_id = nil
2014-01-17 09:32:23 -05:00
if parent_slug_or_id.present?
parent_category_id = Category.query_parent_category(parent_slug_or_id)
2013-10-23 14:40:39 -04:00
raise Discourse::NotFound.new if parent_category_id.blank?
end
@category = Category.query_category(slug_or_id, parent_category_id)
2014-05-12 01:50:31 -04:00
raise Discourse::NotFound.new if !@category
2014-05-12 01:50:31 -04:00
@description_meta = @category.description
guardian.ensure_can_see!(@category)
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)),
2013-11-11 19:35:57 -05:00
category: params[:category],
order: params[:order],
ascending: params[:ascending],
min_posts: params[:min_posts],
max_posts: params[:max_posts],
2014-05-15 10:31:45 -04:00
status: params[:status],
search: params[:search]
}
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
2014-02-25 12:15:20 -05:00
def construct_next_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
2013-12-23 18:50:36 -05:00
2014-02-25 12:15:20 -05:00
def construct_prev_url_with(opts, url_prefix = nil)
method = url_prefix.blank? ? "#{action_name}_path" : "#{url_prefix}_#{action_name}_path"
public_send(method, opts.merge(prev_page_params(opts)))
end
def generate_top_lists(options)
2014-02-06 05:39:43 -05:00
top = TopLists.new
options[:per_page] = SiteSetting.topics_per_period_in_top_summary
2014-01-13 19:02:14 -05:00
topic_query = TopicQuery.new(current_user, options)
if current_user.present?
periods = [ListController.best_period_for(current_user.previous_visit_at, options[:category])]
else
periods = TopTopic.periods
end
2014-01-13 19:02:14 -05:00
2014-02-06 05:39:43 -05:00
periods.each { |period| top.send("#{period}=", topic_query.list_top_for(period)) }
2013-12-23 18:50:36 -05:00
top
end
def self.best_period_for(previous_visit_at, category_id=nil)
best_periods_for(previous_visit_at).each do |period|
top_topics = TopTopic.where("#{period}_score > 0")
if category_id
top_topics = top_topics.joins(:topic).where("topics.category_id = ?", category_id)
end
return period if top_topics.count >= SiteSetting.topics_per_period_in_top_page
end
# default period is yearly
:yearly
end
def self.best_periods_for(date)
date ||= 1.year.ago
periods = []
periods << :daily if date > 8.days.ago
periods << :weekly if date > 35.days.ago
periods << :monthly if date > 180.days.ago
periods << :yearly
periods
2014-01-13 19:02:14 -05:00
end
2013-02-05 14:16:51 -05:00
end