content.rb
上传用户:netsea168
上传日期:2022-07-22
资源大小:4652k
文件大小:11k
- require 'set'
- class Content < ActiveRecord::Base
- belongs_to :text_filter
- has_many :notifications, :foreign_key => 'content_id'
- has_many :notify_users, :through => :notifications,
- :source => 'notify_user',
- :uniq => true
- def notify_users=(collection)
- return notify_users.clear if collection.empty?
- self.class.transaction do
- self.notifications.clear
- collection.uniq.each do |u|
- self.notifications.build(:notify_user => u)
- end
- notify_users.target = collection
- end
- end
- has_many :triggers, :as => :pending_item, :dependent => :delete_all
- named_scope :published_at_like, lambda {|date_at| {:conditions => {
- :published_at => (
- if date_at =~ /d{4}-d{2}-d{2}/
- DateTime.strptime(date_at, '%Y-%m-%d').beginning_of_day..DateTime.strptime(date_at, '%Y-%m-%d').end_of_day
- elsif date_at =~ /d{4}-d{2}/
- DateTime.strptime(date_at, '%Y-%m').beginning_of_month..DateTime.strptime(date_at, '%Y-%m').end_of_month
- elsif date_at =~ /d{4}/
- DateTime.strptime(date_at, '%Y').beginning_of_year..DateTime.strptime(date_at, '%Y').end_of_year
- else
- date_at
- end
- )}
- }
- }
- named_scope :user_id, lambda {|user_id| {:conditions => ['user_id = ?', user_id]}}
- named_scope :published, {:conditions => ['published = ?', true]}
- named_scope :order, lambda {|order_by| {:order => order_by}}
- named_scope :not_published, {:conditions => ['published = ?', false]}
- named_scope :draft, {:conditions => ['state = ?', 'draft']}
- named_scope :no_draft, {:conditions => ['state <> ?', 'draft'], :order => 'created_at DESC'}
- named_scope :searchstring, lambda {|search_string|
- tokens = search_string.split(' ').collect {|c| "%#{c.downcase}%"}
- {:conditions => ['state = ? AND ' + (['(LOWER(body) LIKE ? OR LOWER(extended) LIKE ? OR LOWER(title) LIKE ?)']*tokens.size).join(' AND '),
- "published", *tokens.collect{ |token| [token] * 3 }.flatten]}
- }
- named_scope :already_published, lambda { {:conditions => ['published = ? AND published_at < ?', true, Time.now],
- :order => default_order,
- }}
- serialize :whiteboard
- attr_accessor :just_changed_published_status
- alias_method :just_changed_published_status?, :just_changed_published_status
- include Stateful
- @@content_fields = Hash.new
- @@html_map = Hash.new
- def invalidates_cache?(on_destruction = false)
- if on_destruction
- just_changed_published_status? || published?
- else
- changed? && published? || just_changed_published_status?
- end
- end
- class << self
- # FIXME: Quite a bit of this isn't needed anymore.
- def content_fields(*attribs)
- @@content_fields[self] = ((@@content_fields[self]||[]) + attribs).uniq
- @@html_map[self] = nil
- attribs.each do | field |
- define_method("#{field}=") do | newval |
- if self[field] != newval
- changed
- self[field] = newval
- end
- self[field]
- end
- unless self.method_defined?("#{field}_html")
- define_method("#{field}_html") do
- html(field.to_sym)
- end
- end
- end
- end
- def html_map(field=nil)
- unless @@html_map[self]
- @@html_map[self] = Hash.new
- instance = self.new
- @@content_fields[self].each do |attrib|
- @@html_map[self][attrib] = true
- end
- end
- if field
- @@html_map[self][field]
- else
- @@html_map[self]
- end
- end
- def find_published(what = :all, options = {})
- with_scope(:find => {:order => default_order, :conditions => {:published => true}}) do
- find what, options
- end
- end
- def default_order
- 'published_at DESC'
- end
- def find_already_published(what = :all, at = nil, options = { })
- if what.respond_to?(:has_key?)
- what, options = :all, what
- elsif at.respond_to?(:has_key?)
- options, at = at, nil
- end
- at ||= options.delete(:at) || Time.now
- with_scope(:find => { :conditions => ['published_at < ?', at]}) do
- find_published(what, options)
- end
- end
- def find_by_published_at(column_name = :published_at)
- from_where = "FROM #{self.table_name} WHERE #{column_name} is not NULL AND type='#{self.name}'"
- # Implement adapter-specific groupings below, or allow us to fall through to the generic ruby-side grouping
- if defined?(ActiveRecord::ConnectionAdapters::MysqlAdapter) && self.connection.is_a?(ActiveRecord::ConnectionAdapters::MysqlAdapter)
- # MySQL uses date_format
- find_by_sql("SELECT date_format(#{column_name}, '%Y-%m') AS publication #{from_where} GROUP BY publication ORDER BY publication DESC")
- elsif defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) && self.connection.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
- # PostgreSQL uses to_char
- find_by_sql("SELECT to_char(#{column_name}, 'YYYY-MM') AS publication #{from_where} GROUP BY publication ORDER BY publication DESC")
- else
- # If we don't have an adapter-safe conversion from date -> YYYY-MM,
- # we'll do the GROUP BY server-side. There won't be very many objects
- # in this array anyway.
- date_map = {}
- dates = find_by_sql("SELECT #{column_name} AS publication #{from_where}")
- dates.map! do |d|
- d.publication = Time.parse(d.publication).strftime('%Y-%m')
- d.freeze
- if !date_map.has_key?(d.publication)
- date_map[d.publication] = true
- d
- end
- end
- dates.reject!{|d| d.blank? || d.publication.blank?}
- dates.sort!{|a,b| b.publication <=> a.publication}
- dates
- end
- end
- def function_search_no_draft(search_hash)
- list_function = []
- if search_hash.nil?
- search_hash = {}
- end
- if search_hash[:searchstring]
- list_function << 'searchstring(search_hash[:searchstring])' unless search_hash[:searchstring].to_s.empty?
- end
- if search_hash[:published_at] and %r{(dddd)-(dd)} =~ search_hash[:published_at]
- list_function << 'published_at_like(search_hash[:published_at])'
- end
- if search_hash[:user_id] && search_hash[:user_id].to_i > 0
- list_function << 'user_id(search_hash[:user_id])'
- end
- if search_hash[:published]
- list_function << 'published' if search_hash[:published].to_s == '1'
- list_function << 'not_published' if search_hash[:published].to_s == '0'
- end
-
- list_function
- end
- end
- def content_fields
- @@content_fields[self.class]
- end
- def html_map(field=nil)
- self.class.html_map(field)
- end
- def cache_key(field)
- id ? "contents_html/#{id}/#{field}" : nil
- end
- # Return HTML for some part of this object. It will be fetched from the
- # cache if possible, or regenerated if needed.
- def html(field = :all)
- if field == :all
- generate_html(:all, content_fields.map{|f| self[f].to_s}.join("nn"))
- elsif self.class.html_map(field)
- generate_html(field)
- else
- raise "Unknown field: #{field.inspect} in content.html"
- end
- end
- # Generate HTML for a specific field using the text_filter in use for this
- # object. The HTML is cached in the fragment cache, using the +ContentCache+
- # object in @@cache.
- def generate_html(field, text = nil)
- text ||= self[field].to_s
- html = text_filter.filter_text_for_content(blog, text, self) || text
- html_postprocess(field,html).to_s
- end
- # Post-process the HTML. This is a noop by default, but Comment overrides it
- # to enforce HTML sanity.
- def html_postprocess(field,html)
- html
- end
- def whiteboard
- self[:whiteboard] ||= Hash.new
- end
- # The default text filter. Generally, this is the filter specified by blog.text_filter,
- # but comments may use a different default.
- def default_text_filter
- blog.text_filter.to_text_filter
- end
- # Grab the text filter for this object. It's either the filter specified by
- # self.text_filter_id, or the default specified in the default blog object.
- def text_filter
- if self[:text_filter_id] && !self[:text_filter_id].zero?
- TextFilter.find(self[:text_filter_id])
- else
- default_text_filter
- end
- end
- # Set the text filter for this object.
- def text_filter=(filter)
- returning(filter.to_text_filter) do |tf|
- if tf.id != text_filter_id
- changed if !new_record? && published?
- end
- self.text_filter_id = tf.id
- end
- end
- # Changing the title flags the object as changed
- def title=(new_title)
- if new_title == self[:title]
- self[:title]
- else
- changed if !new_record? && published?
- self[:title] = new_title
- end
- end
- def blog
- @blog ||= Blog.default
- end
- def publish!
- self.published = true
- self.save!
- end
- def withdraw!
- self.withdraw
- self.save!
- end
- def published_at
- self[:published_at] || self[:created_at]
- end
- def send_notification_to_user(user)
- notify_user_via_email(user)
- end
- def really_send_notifications
- returning true do
- interested_users.each do |value|
- send_notification_to_user(value)
- end
- end
- end
- def to_atom xml
- xml.entry self, :url => permalink_url do |entry|
- atom_author(entry)
- atom_title(entry)
- atom_groupings(entry)
- atom_enclosures(entry)
- atom_content(entry)
- end
- end
- def to_rss(xml)
- xml.item do
- rss_title(xml)
- rss_description(xml)
- xml.pubDate published_at.rfc822
- xml.guid "urn:uuid:#{guid}", :isPermaLink => "false"
- rss_author(xml)
- rss_comments(xml)
- rss_groupings(xml)
- rss_enclosure(xml)
- rss_trackback(xml)
- xml.link normalized_permalink_url
- end
- end
- def rss_comments(xml)
- end
- def rss_description(xml)
- post = html(blog.show_extended_on_rss ? :all : :body)
- if blog.rss_description
- if respond_to?(:user) && self.user && self.user.name
- rss_desc = "<hr /><p><small>#{_('Original article writen by')} #{self.user.name} #{_('and published on')} <a href='#{blog.base_url}'>#{blog.blog_name}</a> | <a href='#{self.permalink_url}'>#{_('direct link to this article')}</a> | #{_('If you are reading this article elsewhere than')} <a href='#{blog.base_url}'>#{blog.blog_name}</a>, #{_('it has been illegally reproduced and without proper authorization')}.</small></p>"
- else
- rss_desc = ""
- end
- post = post + rss_desc
- end
- xml.description(post)
- end
- def rss_groupings(xml)
- end
- def rss_enclosure(xml)
- end
- def rss_trackback(xml)
- end
- def atom_groupings(xml)
- end
- def atom_enclosures(xml)
- end
- def atom_content(entry)
- entry.content(html(:all), :type => 'html')
- end
- # TODO: Perhaps permalink_url should produce valid URI's instead of IRI's
- def normalized_permalink_url
- @normalized_permalink_url ||= Addressable::URI.parse(permalink_url).normalize
- end
- end
- class Object
- def to_text_filter
- TextFilter.find_by_name(self.to_s) || TextFilter.find_by_name('none')
- end
- end
- class ContentTextHelpers
- include ActionView::Helpers::UrlHelper
- include ActionView::Helpers::TagHelper
- include ActionView::Helpers::SanitizeHelper
- include ActionView::Helpers::TextHelper
- extend ActionView::Helpers::SanitizeHelper::ClassMethods
- end