bborn/communityengine

View on GitHub
app/models/post.rb

Summary

Maintainability
B
4 hrs
Test Coverage
class Post < ActiveRecord::Base
  include Rakismet::Model
  rakismet_attrs :comment_type => 'post'

  acts_as_moderated_commentable

  acts_as_taggable
  acts_as_activity :user, :if => Proc.new{|r| r.is_live?}
  acts_as_publishable :live, :draft

  belongs_to :user
  belongs_to :category
  has_many   :polls, :dependent => :destroy
  has_many :favorites, :as => :favoritable, :dependent => :destroy

  validates_presence_of :raw_post
  validates_presence_of :title
  validates_presence_of :user
  validates_presence_of :published_at, :if => Proc.new{|r| r.is_live? }

  before_save :transform_post, :if => Proc.new{|r| r.raw_post_changed? }
  before_validation :set_published_at

  after_save do |post|
    activity = Activity.find_by_item_type_and_item_id('Post', post.id)
    if post.is_live? && !activity
      post.create_activity_from_self
    elsif post.is_draft? && activity
      activity.destroy
    end
  end

  attr_accessor :invalid_emails

  # Class Methods
  class << self

    # Scopes
    def by_featured_writers
      includes(:user).where("users.featured_writer = ?", true).references(:users)
    end
    def popular
      order('posts.view_count DESC')
    end
    def since(days)
      where("posts.published_at > ?", days.ago)
    end
    def recent
      order("posts.published_at DESC")
    end

    def find_related_to(post, options = {})
      options.reverse_merge!({:limit => 8,
          :order => 'posts.published_at DESC',
          :conditions => [ 'posts.id != ? AND published_as = ?', post.id, 'live' ]
      })

      limit(options[:limit]).order(options[:order]).where(options[:conditions]).tagged_with(post.tag_list, :any => true)
    end

    def find_recent(options = {:limit => 5})
      recent.limit(options[:limit])
    end

    def find_popular(options = {} )
      options.reverse_merge! :limit => 5, :since => 7.days

      self.popular.since(options[:since]).limit(options[:limit])
    end

    def find_featured(options = {:limit => 10})
      self.recent.by_featured_writers.limit(options[:limit])
    end

    def find_most_commented(limit = 10, since = 7.days.ago)
      Post.select('posts.*', 'count(*) as comments_count')
      .joins("LEFT JOIN comments ON comments.commentable_id = posts.id")
      .where('comments.commentable_type = ? AND posts.published_at > ?', 'Post', since)
      .references('comments')
      .group(self.columns.map{|column| self.table_name + "." + column.name}.join(","))
      .order('comments_count DESC')
      .limit(limit)
    end

    def new_from_bookmarklet(params)
      self.new(
        :title => "#{params[:title] || params[:uri]}",
        :raw_post => "<a href='#{params[:uri]}'>#{params[:uri]}</a>#{params[:selection] ? "<p>#{params[:selection]}</p>" : ''}"
        )
    end

  end




  def to_param
    id.to_s << "-" << (title ? title.parameterize : '' )
  end

  def display_title
    t = self.title
    if self.category
      t = self.category.name.upcase << ": " << t
    end
    t
  end

  def previous_post
    self.user.posts.order('published_at DESC').where('published_at < ? and published_as = ?', published_at, 'live').first
  end
  def next_post
    self.user.posts.except(:order).order('published_at DESC').where('published_at > ? and published_as = ?', published_at, 'live').first
  end

  def first_image_in_body(size = nil, options = {})
    doc = Nokogiri::HTML( post )
    image = doc.at("img")
    image ? image['src'] : nil
  end

  def tag_for_first_image_in_body
    image = first_image_in_body
    image.nil? ? '' : "<img src='#{image}' />"
  end

  ## transform the text and title into valid html
  def transform_post
   self.post  = white_list(self.raw_post)
   self.title = white_list(self.title)
  end

  def set_published_at
    if self.is_live? && !self.published_at
      self.published_at = Time.now
    end
  end

  def owner
    self.user
  end

  def send_to(email_addresses = '', message = '', user = nil)
    self.invalid_emails = []
    emails = email_addresses.split(",").collect{|email| email.strip }.uniq
    emails.each do |email|
      self.invalid_emails << email unless email =~ /[\w._%-]+@[\w.-]+.[a-zA-Z]{2,4}/
    end
    if email_addresses.blank? || !invalid_emails.empty?
      return false
    else
      emails = email_addresses.split(",").collect{|email| email.strip }.uniq
      emails.each{|email|
        UserNotifier.post_recommendation((user ? user.login : 'Someone'), email, self, message, user).deliver
      }
      self.increment(:emailed_count).save
    end
  end

  def image_for_excerpt
    first_image_in_body || user.avatar_photo_url(:medium)
  end

  def create_poll(poll, choices)
    new_poll = self.polls.new(:question => poll[:question])
    choices.delete('')
    if choices.size > 1
      new_poll.save
      new_poll.add_choices(choices)
    end
  end

  def update_poll(poll, choices)
    return unless self.poll
    self.poll.update_attributes(:question => poll[:question])
    choices.delete('')
    if choices.size > 1
      self.poll.choices.destroy_all
      self.poll.save
      self.poll.add_choices(choices)
    else
      self.poll.destroy
    end
  end

  def poll
    !polls.empty? && polls.first
  end

  def has_been_favorited_by(user = nil, remote_ip = nil)
    f = Favorite.find_by_user_or_ip_address(self, user, remote_ip)
    return f
  end

  def published_at_display(format = :published_date)
    is_live? ? I18n.l(published_at, :format => format.to_sym) : 'Draft'
  end

end