<commit_before># coding: utf-8
require 'uri'
require 'net/http'

class Article < Content
  include TypoGuid
  include ConfigManager

  serialize :settings, Hash

  content_fields :body, :extended

  validates_uniqueness_of :guid
  validates_presence_of :title

  belongs_to :user

  has_many :pings, :dependent => :destroy, :order => "created_at ASC"
  has_many :trackbacks, :dependent => :destroy, :order => "created_at ASC"
  has_many :feedback, :order => "created_at DESC"
  has_many :resources, :order => "created_at DESC", :dependent => :nullify
  has_many :categorizations
  has_many :categories, :through => :categorizations
  has_many :triggers, :as => :pending_item

  has_many :comments,   :dependent => :destroy, :order => "created_at ASC" do

    # Get only ham or presumed_ham comments
    def ham
      where(:state => ["presumed_ham", "ham"])
    end

    # Get only spam or presumed_spam comments
    def spam
      where(:state => ["presumed_spam", "spam"])
    end

  end

  with_options(:conditions => { :published => true }, :order => 'created_at ASC') do |this|
    this.has_many :published_comments, class_name: "Comment"
    this.has_many :published_trackbacks, class_name: "Trackback"
    this.has_many :published_feedback, class_name: "Feedback"
  end

  has_and_belongs_to_many :tags

  before_create :create_guid
  before_save :set_published_at, :ensure_settings_type, :set_permalink
  after_save :post_trigger, :keywords_to_tags, :shorten_url

  scope :category, lambda { |category_id| where('categorizations.category_id = ?', category_id).includes('categorizations') }
  scope :drafts, lambda { where(state: 'draft').order('created_at DESC') }
  scope :child_of, lambda { |article_id| where(parent_id: article_id) }
  scope :published, lambda { where(published: true, published_at: Time.at(0)..Time.now).order('published_at DESC') }
  scope :published_at, lambda {|time_params| published.where(published_at: TypoTime.delta(*time_params)).order('published_at DESC')}
  scope :published_since, lambda {|time| published.where('published_at > ?', time).order('published_at DESC') }
  scope :withdrawn, lambda { where(state: 'withdrawn').order('published_at DESC') }
  scope :pending, lambda { where('state = ? and published_at > ?', 'publication_pending', Time.now).order('published_at DESC') }

  scope :bestof, ->() {
    joins(:feedback).
      where('feedback.published' => true, 'feedback.type' => 'Comment',
            'contents.published' => true).
      group('contents.id').
      order('count(feedback.id) DESC').
      select('contents.*, count(feedback.id) as comment_count').
      limit(5)
  }

  setting :password, :string, ''

  attr_accessor :draft, :keywords

  include Article::States

  has_state(:state, :valid_states  => [:new, :draft,
                                       :publication_pending, :just_published, :published,
                                       :just_withdrawn, :withdrawn],
                                       :initial_state =>  :new,
                                       :handles       => [:withdraw,
                                                          :post_trigger,
                                                          :send_pings, :send_notifications,
                                                          :published_at=, :just_published?])

  def initialize(*args)
    super
    # Yes, this is weird - PDC
    begin
      self.settings ||= {}
    rescue
      self.settings = {}
    end
  end

  def set_permalink
    return if self.state == 'draft' || self.permalink.present?
    self.permalink = self.title.to_permalink
  end

  def set_author(user)
    self.author = user.login
    self.user = user
  end

  def has_child?
    Article.exists?(parent_id: self.id)
  end

  def self.last_draft(article_id)
    article = Article.find(article_id)
    while article.has_child?
      article = Article.child_of(article.id).first
    end
    article
  end

  def self.search_with_pagination(search_hash, paginate_hash)
    state = (search_hash[:state] and ["no_draft", "drafts", "published", "withdrawn", "pending"].include? search_hash[:state]) ? search_hash[:state] : nil

    if state.nil?
      list_function  = function_search_all_posts(search_hash)
    elsif
      list_function  = ["Article.#{state}"] + function_search_all_posts(search_hash)
    end

    if search_hash[:category] && search_hash[:category].to_i > 0
      list_function << 'category(search_hash[:category])'
    end

    list_function << "page(paginate_hash[:page])"
    list_function << "per(paginate_hash[:per_page])"
    list_function << "order('published_at desc, created_at desc')"
    eval(list_function.join('.'))
  end

  def permalink_url(anchor=nil, only_path=false)
    @cached_permalink_url ||= {}
    @cached_permalink_url["#{anchor}#{only_path}"] ||= blog.url_for(permalink_url_options, anchor: anchor, only_path: only_path)
  end

  def save_attachments!(files)
    files ||= {}
    files.values.each { |f| self.save_attachment!(f) }
  end

  def save_attachment!(file)
    self.resources << Resource.create_and_upload(file)
  rescue => e
    logger.info(e.message)
  end

  def trackback_url
    blog.url_for("trackbacks?article_id=#{self.id}", :only_path => false)
  end

  def comment_url
    blog.url_for("comments?article_id=#{self.id}", :only_path => false)
  end

  def preview_comment_url
    blog.url_for("comments/preview?article_id=#{self.id}", :only_path => false)
  end

  def feed_url(format)
    "#{permalink_url}.#{format.gsub(/\d/,'')}"
  end

  def really_send_pings<commit_msg>comments: use relative URLs for comment forms.<commit_after># coding: utf-8
require 'uri'
require 'net/http'

class Article < Content
  include TypoGuid
  include ConfigManager

  serialize :settings, Hash

  content_fields :body, :extended

  validates_uniqueness_of :guid
  validates_presence_of :title

  belongs_to :user

  has_many :pings, :dependent => :destroy, :order => "created_at ASC"
  has_many :trackbacks, :dependent => :destroy, :order => "created_at ASC"
  has_many :feedback, :order => "created_at DESC"
  has_many :resources, :order => "created_at DESC", :dependent => :nullify
  has_many :categorizations
  has_many :categories, :through => :categorizations
  has_many :triggers, :as => :pending_item

  has_many :comments,   :dependent => :destroy, :order => "created_at ASC" do

    # Get only ham or presumed_ham comments
    def ham
      where(:state => ["presumed_ham", "ham"])
    end

    # Get only spam or presumed_spam comments
    def spam
      where(:state => ["presumed_spam", "spam"])
    end

  end

  with_options(:conditions => { :published => true }, :order => 'created_at ASC') do |this|
    this.has_many :published_comments, class_name: "Comment"
    this.has_many :published_trackbacks, class_name: "Trackback"
    this.has_many :published_feedback, class_name: "Feedback"
  end

  has_and_belongs_to_many :tags

  before_create :create_guid
  before_save :set_published_at, :ensure_settings_type, :set_permalink
  after_save :post_trigger, :keywords_to_tags, :shorten_url

  scope :category, lambda { |category_id| where('categorizations.category_id = ?', category_id).includes('categorizations') }
  scope :drafts, lambda { where(state: 'draft').order('created_at DESC') }
  scope :child_of, lambda { |article_id| where(parent_id: article_id) }
  scope :published, lambda { where(published: true, published_at: Time.at(0)..Time.now).order('published_at DESC') }
  scope :published_at, lambda {|time_params| published.where(published_at: TypoTime.delta(*time_params)).order('published_at DESC')}
  scope :published_since, lambda {|time| published.where('published_at > ?', time).order('published_at DESC') }
  scope :withdrawn, lambda { where(state: 'withdrawn').order('published_at DESC') }
  scope :pending, lambda { where('state = ? and published_at > ?', 'publication_pending', Time.now).order('published_at DESC') }

  scope :bestof, ->() {
    joins(:feedback).
      where('feedback.published' => true, 'feedback.type' => 'Comment',
            'contents.published' => true).
      group('contents.id').
      order('count(feedback.id) DESC').
      select('contents.*, count(feedback.id) as comment_count').
      limit(5)
  }

  setting :password, :string, ''

  attr_accessor :draft, :keywords

  include Article::States

  has_state(:state, :valid_states  => [:new, :draft,
                                       :publication_pending, :just_published, :published,
                                       :just_withdrawn, :withdrawn],
                                       :initial_state =>  :new,
                                       :handles       => [:withdraw,
                                                          :post_trigger,
                                                          :send_pings, :send_notifications,
                                                          :published_at=, :just_published?])

  def initialize(*args)
    super
    # Yes, this is weird - PDC
    begin
      self.settings ||= {}
    rescue
      self.settings = {}
    end
  end

  def set_permalink
    return if self.state == 'draft' || self.permalink.present?
    self.permalink = self.title.to_permalink
  end

  def set_author(user)
    self.author = user.login
    self.user = user
  end

  def has_child?
    Article.exists?(parent_id: self.id)
  end

  def self.last_draft(article_id)
    article = Article.find(article_id)
    while article.has_child?
      article = Article.child_of(article.id).first
    end
    article
  end

  def self.search_with_pagination(search_hash, paginate_hash)
    state = (search_hash[:state] and ["no_draft", "drafts", "published", "withdrawn", "pending"].include? search_hash[:state]) ? search_hash[:state] : nil

    if state.nil?
      list_function  = function_search_all_posts(search_hash)
    elsif
      list_function  = ["Article.#{state}"] + function_search_all_posts(search_hash)
    end

    if search_hash[:category] && search_hash[:category].to_i > 0
      list_function << 'category(search_hash[:category])'
    end

    list_function << "page(paginate_hash[:page])"
    list_function << "per(paginate_hash[:per_page])"
    list_function << "order('published_at desc, created_at desc')"
    eval(list_function.join('.'))
  end

  def permalink_url(anchor=nil, only_path=false)
    @cached_permalink_url ||= {}
    @cached_permalink_url["#{anchor}#{only_path}"] ||= blog.url_for(permalink_url_options, anchor: anchor, only_path: only_path)
  end

  def save_attachments!(files)
    files ||= {}
    files.values.each { |f| self.save_attachment!(f) }
  end

  def save_attachment!(file)
    self.resources << Resource.create_and_upload(file)
  rescue => e
    logger.info(e.message)
  end

  def trackback_url
    blog.url_for("trackbacks?article_id=#{self.id}", :only_path => false)
  end

  def comment_url
    blog.url_for("comments?article_id=#{self.id}", :only_path => true)
  end

  def preview_comment_url
    blog.url_for("comments/preview?article_id=#{self.id}", :only_path => true)
  end

  def feed_url(format)
    "#{permalink_url}.#{format.gsub(/\d/,'')}"
  end

  def really_send_pings
{'fraction_non_alphanumeric': 0.12771666219479474, 'fraction_numerical': 0.0007154995080940882, 'mean_word_length': 3.2711993888464477, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 63, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 20, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1317661', 'n_tokens_mistral': 3615, 'n_tokens_neox': 3507, 'n_words': 733}