discourse/app/controllers/list_controller.rb
Sam 03ea0bfe22 FEATURE: allow users to archive messages
Messages are now in 3 buckets

- Inbox for all new messages
- Sent for all sent messages
- Archive for all messages you are done with

You can select messages from your Inbox or Sent and move them to your Archive,
you can move messages out of your Archive similarly

Similar concept applied to group messages, except that archiving and unarchiving
will apply to all group members
2015-12-23 11:09:30 +11:00

332 lines
11 KiB
Ruby

require_dependency 'topic_list_responder'
class ListController < ApplicationController
include TopicListResponder
skip_before_filter :check_xhr
before_filter :set_category, only: [
# filtered topics lists
Discourse.filters.map { |f| :"category_#{f}" },
Discourse.filters.map { |f| :"category_none_#{f}" },
Discourse.filters.map { |f| :"parent_category_category_#{f}" },
Discourse.filters.map { |f| :"parent_category_category_none_#{f}" },
# top summaries
:category_top,
:category_none_top,
:parent_category_category_top,
# top pages (ie. with a period)
TopTopic.periods.map { |p| :"category_top_#{p}" },
TopTopic.periods.map { |p| :"category_none_top_#{p}" },
TopTopic.periods.map { |p| :"parent_category_category_top_#{p}" },
# category feeds
:category_feed,
].flatten
before_filter :ensure_logged_in, except: [
:topics_by,
# anonymous filters
Discourse.anonymous_filters,
Discourse.anonymous_filters.map { |f| "#{f}_feed" },
# anonymous categorized filters
Discourse.anonymous_filters.map { |f| :"category_#{f}" },
Discourse.anonymous_filters.map { |f| :"category_none_#{f}" },
Discourse.anonymous_filters.map { |f| :"parent_category_category_#{f}" },
Discourse.anonymous_filters.map { |f| :"parent_category_category_none_#{f}" },
# 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}" },
TopTopic.periods.map { |p| :"category_top_#{p}" },
TopTopic.periods.map { |p| :"category_none_top_#{p}" },
TopTopic.periods.map { |p| :"parent_category_category_top_#{p}" },
].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
if filter == :latest && params[:category].blank?
list_opts[:no_definitions] = true
end
if filter.to_s == current_homepage
list_opts.merge!(exclude_category_ids: get_excluded_category_ids(list_opts[:category]))
end
list = TopicQuery.new(user, list_opts).public_send("list_#{filter}")
list.more_topics_url = construct_url_with(:next, list_opts)
list.prev_topics_url = construct_url_with(:prev, list_opts)
if Discourse.anonymous_filters.include?(filter)
@description = SiteSetting.site_description
@rss = filter
# Note the first is the default and we don't add a title
if (filter.to_s != current_homepage) && use_crawler_layout?
filter_title = I18n.t("js.filters.#{filter.to_s}.title", count: 0)
if list_opts[:category]
@title = I18n.t('js.filters.with_category', filter: filter_title, category: Category.find(list_opts[:category]).name)
else
@title = I18n.t('js.filters.with_topics', filter: filter_title)
end
end
end
respond_with_list(list)
end
define_method("category_#{filter}") do
canonical_url "#{Discourse.base_url_no_prefix}#{@category.url}"
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
canonical_url "#{Discourse.base_url_no_prefix}#{@category.url}"
self.send(filter, category: @category.id)
end
define_method("parent_category_category_none_#{filter}") do
self.send(filter, category: @category.id)
end
end
[:topics_by, :private_messages, :private_messages_sent, :private_messages_unread, :private_messages_archive, :private_messages_group, :private_messages_group_archive].each do |action|
define_method("#{action}") do
list_opts = build_topic_list_options
target_user = fetch_user_from_params(include_inactive: current_user.try(:staff?))
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
list.more_topics_url = url_for(construct_url_with(:next, list_opts, url_prefix))
list.prev_topics_url = url_for(construct_url_with(:prev, list_opts, url_prefix))
respond_with_list(list)
end
end
def latest_feed
discourse_expires_in 1.minute
@title = "#{SiteSetting.title} - #{I18n.t("rss_description.latest")}"
@link = "#{Discourse.base_url}/latest"
@atom_link = "#{Discourse.base_url}/latest.rss"
@description = I18n.t("rss_description.latest")
@topic_list = TopicQuery.new(nil, order: 'created').list_latest
render 'list', formats: [:rss]
end
def category_feed
guardian.ensure_can_see!(@category)
discourse_expires_in 1.minute
@title = @category.name
@link = "#{Discourse.base_url}#{@category.url}"
@atom_link = "#{Discourse.base_url}#{@category.url}.rss"
@description = "#{I18n.t('topics_in_category', category: @category.name)} #{@category.description}"
@topic_list = TopicQuery.new.list_new_in_category(@category)
render 'list', formats: [:rss]
end
def top(options=nil)
options ||= {}
period = ListController.best_period_for(current_user.try(:previous_visit_at), options[:category])
send("top_#{period}", options)
end
def category_top
top(category: @category.id)
end
def category_none_top
top(category: @category.id, no_subcategories: true)
end
def parent_category_category_top
top(category: @category.id)
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
if "top".freeze == current_homepage
top_options.merge!(exclude_category_ids: get_excluded_category_ids(top_options[:category]))
end
user = list_target_user
list = TopicQuery.new(user, top_options).list_top_for(period)
list.for_period = period
list.more_topics_url = construct_url_with(:next, top_options)
list.prev_topics_url = construct_url_with(:prev, top_options)
if use_crawler_layout?
@title = I18n.t("js.filters.top.#{period}.title")
end
respond_with_list(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_top_#{period}") do
self.send("top_#{period}", category: @category.id)
end
end
protected
def next_page_params(opts = nil)
page_params(opts).merge(page: params[:page].to_i + 1)
end
def prev_page_params(opts = nil)
pg = params[:page].to_i
if pg > 1
page_params(opts).merge(page: pg - 1)
else
page_params(opts).merge(page: nil)
end
end
private
def page_params(opts = nil)
opts ||= {}
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
end
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)
redirect_or_not_found and return if parent_category_id.blank?
end
@category = Category.query_category(slug_or_id, parent_category_id)
redirect_or_not_found and return if !@category
@description_meta = @category.description_text
raise Discourse::NotFound unless guardian.can_see?(@category)
end
def build_topic_list_options
options = {
page: params[:page],
topic_ids: param_to_integer_list(:topic_ids),
exclude_category_ids: params[:exclude_category_ids],
category: params[:category],
order: params[:order],
ascending: params[:ascending],
min_posts: params[:min_posts],
max_posts: params[:max_posts],
status: params[:status],
filter: params[:filter],
state: params[:state],
search: params[:search],
q: params[:q],
group_name: params[:group_name]
}
options[:no_subcategories] = true if params[:no_subcategories] == 'true'
options[:slow_platform] = true if slow_platform?
options
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(action, opts, url_prefix = nil)
method = url_prefix.blank? ? "#{action_name}_path" : "#{url_prefix}_#{action_name}_path"
url = if action == :prev
public_send(method, opts.merge(prev_page_params(opts)))
else # :next
public_send(method, opts.merge(next_page_params(opts)))
end
url.sub('.json?','?')
end
def get_excluded_category_ids(current_category=nil)
exclude_category_ids = Category.where(suppress_from_homepage: true)
exclude_category_ids = exclude_category_ids.where.not(id: current_category) if current_category
exclude_category_ids.pluck(:id)
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")
top_topics = top_topics.joins(:topic).where("topics.category_id = ?", category_id) if category_id
return period if top_topics.count >= SiteSetting.topics_per_period_in_top_page
end
# default period is yearly
SiteSetting.top_page_default_timeframe
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
end
def redirect_or_not_found
url = request.fullpath
permalink = Permalink.find_by_url(url)
if permalink.present?
# permalink present, redirect to that URL
if permalink.external_url
redirect_to permalink.external_url, status: :moved_permanently
elsif permalink.target_url
redirect_to "#{Discourse::base_uri}#{permalink.target_url}", status: :moved_permanently
else
raise Discourse::NotFound
end
else
# redirect to 404
raise Discourse::NotFound
end
end
end