mirror of
https://github.com/discourse/discourse.git
synced 2024-11-27 18:43:38 +08:00
0d01c33482
All models are now using ActiveModel::ForbiddenAttributesProtection, which shifts the responsibility for parameter whitelisting for mass-assignments from the model to the controller. attr_accessible has been disabled and removed as this functionality replaces that. The require_parameters method in the ApplicationController has been removed in favor of strong_parameters' #require method. It is important to note that there is still some refactoring required to get all parameters to pass through #require and #permit so that we can guarantee that parameter values are scalar. Currently strong_parameters, in most cases, is only being utilized to require parameters and to whitelist the few places that do mass-assignments.
174 lines
5.2 KiB
Ruby
174 lines
5.2 KiB
Ruby
class Category < ActiveRecord::Base
|
|
belongs_to :topic, dependent: :destroy
|
|
belongs_to :topic_only_relative_url,
|
|
select: "id, title, slug",
|
|
class_name: "Topic",
|
|
foreign_key: "topic_id"
|
|
belongs_to :user
|
|
|
|
has_many :topics
|
|
has_many :category_featured_topics
|
|
has_many :featured_topics, through: :category_featured_topics, source: :topic
|
|
|
|
has_many :category_featured_users
|
|
has_many :featured_users, through: :category_featured_users, source: :user
|
|
|
|
has_many :category_groups
|
|
has_many :groups, through: :category_groups
|
|
|
|
validates :user_id, presence: true
|
|
validates :name, presence: true, uniqueness: true, length: { in: 1..50 }
|
|
validate :uncategorized_validator
|
|
|
|
before_validation :ensure_slug
|
|
after_save :invalidate_site_cache
|
|
after_create :create_category_definition
|
|
after_create :publish_categories_list
|
|
after_destroy :invalidate_site_cache
|
|
after_destroy :publish_categories_list
|
|
|
|
has_one :category_search_data
|
|
|
|
scope :latest, ->{ order('topic_count desc') }
|
|
|
|
scope :secured, ->(guardian = nil) {
|
|
ids = guardian.secure_category_ids if guardian
|
|
if ids.present?
|
|
where("NOT categories.secure or categories.id in (:cats)", cats: ids)
|
|
else
|
|
where("NOT categories.secure")
|
|
end
|
|
}
|
|
|
|
delegate :post_template, to: 'self.class'
|
|
|
|
attr_accessor :displayable_topics
|
|
|
|
# Internal: Update category stats: # of topics in past year, month, week for
|
|
# all categories.
|
|
def self.update_stats
|
|
topics = Topic
|
|
.select("COUNT(*)")
|
|
.where("topics.category_id = categories.id")
|
|
.where("categories.topic_id <> topics.id")
|
|
.visible
|
|
|
|
topic_count = topics.to_sql
|
|
topics_year = topics.created_since(1.year.ago).to_sql
|
|
topics_month = topics.created_since(1.month.ago).to_sql
|
|
topics_week = topics.created_since(1.week.ago).to_sql
|
|
|
|
Category.update_all("topic_count = (#{topic_count}),
|
|
topics_year = (#{topics_year}),
|
|
topics_month = (#{topics_month}),
|
|
topics_week = (#{topics_week})")
|
|
end
|
|
|
|
# Internal: Generate the text of post prompting to enter category
|
|
# description.
|
|
def self.post_template
|
|
I18n.t("category.post_template", replace_paragraph: I18n.t("category.replace_paragraph"))
|
|
end
|
|
|
|
def create_category_definition
|
|
create_topic!(title: I18n.t("category.topic_prefix", category: name), user: user, pinned_at: Time.now)
|
|
update_column(:topic_id, topic.id)
|
|
topic.update_column(:category_id, id)
|
|
topic.posts.create(raw: post_template, user: user)
|
|
end
|
|
|
|
def topic_url
|
|
topic_only_relative_url.try(:relative_url)
|
|
end
|
|
|
|
def ensure_slug
|
|
if name.present?
|
|
self.slug = Slug.for(name)
|
|
|
|
return if self.slug.blank?
|
|
|
|
# If a category with that slug already exists, set the slug to nil so the category can be found
|
|
# another way.
|
|
category = Category.where(slug: self.slug)
|
|
category = category.where("id != ?", id) if id.present?
|
|
self.slug = '' if category.exists?
|
|
end
|
|
end
|
|
|
|
# Categories are cached in the site json, so the caches need to be
|
|
# invalidated whenever the category changes.
|
|
def invalidate_site_cache
|
|
Site.invalidate_cache
|
|
end
|
|
|
|
def publish_categories_list
|
|
MessageBus.publish('/categories', {categories: ActiveModel::ArraySerializer.new(Category.latest.all).as_json})
|
|
end
|
|
|
|
def uncategorized_validator
|
|
errors.add(:name, I18n.t(:is_reserved)) if name == SiteSetting.uncategorized_name
|
|
errors.add(:slug, I18n.t(:is_reserved)) if slug == SiteSetting.uncategorized_name
|
|
end
|
|
|
|
def group_names=(names)
|
|
# this line bothers me, destroying in AR can not seem to be queued, thinking of extending it
|
|
category_groups.destroy_all unless new_record?
|
|
ids = Group.where(name: names.split(",")).pluck(:id)
|
|
ids.each do |id|
|
|
category_groups.build(group_id: id)
|
|
end
|
|
end
|
|
|
|
def deny(group)
|
|
if group == :all
|
|
self.secure = true
|
|
end
|
|
end
|
|
|
|
def allow(group)
|
|
if group == :all
|
|
self.secure = false
|
|
# this is kind of annoying, there should be a clean way of queuing this stuff
|
|
category_groups.destroy_all unless new_record?
|
|
else
|
|
groups.push(group)
|
|
end
|
|
end
|
|
|
|
def secure_group_ids
|
|
if self.secure
|
|
groups.pluck("groups.id")
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
# == Schema Information
|
|
#
|
|
# Table name: categories
|
|
#
|
|
# id :integer not null, primary key
|
|
# name :string(50) not null
|
|
# color :string(6) default("AB9364"), not null
|
|
# topic_id :integer
|
|
# topic_count :integer default(0), not null
|
|
# created_at :datetime not null
|
|
# updated_at :datetime not null
|
|
# user_id :integer not null
|
|
# topics_year :integer
|
|
# topics_month :integer
|
|
# topics_week :integer
|
|
# slug :string(255) not null
|
|
# description :text
|
|
# text_color :string(6) default("FFFFFF"), not null
|
|
# hotness :float default(5.0), not null
|
|
# secure :boolean default(FALSE), not null
|
|
# auto_close_days :float
|
|
#
|
|
# Indexes
|
|
#
|
|
# index_categories_on_forum_thread_count (topic_count)
|
|
# index_categories_on_name (name) UNIQUE
|
|
#
|
|
|