<commit_before>class Paper < ActiveRecord::Base
  include SettingsHelper
  serialize :activities, Hash

  belongs_to  :submitting_author,
              :class_name => 'User',
              :validate => true,
              :foreign_key => "user_id"

  belongs_to  :editor

  include AASM

  aasm :column => :state do
    state :submitted, :initial => true
    state :review_pending
    state :under_review
    state :review_completed
    state :superceded
    state :accepted
    state :rejected
    state :withdrawn

    event :reject do
      transitions :to => :rejected
    end

    event :start_meta_review do
      transitions :from => :submitted, :to => :review_pending, :if => :create_meta_review_issue
    end

    event :start_review do
      transitions :from => :review_pending, :to => :under_review, :if => :create_review_issue
    end

    event :accept do
      transitions :to => :accepted
    end

    event :withdraw do
      transitions :to => :withdrawn
    end
  end

  VISIBLE_STATES = [
    "accepted",
    "superceded"
  ].freeze

  IN_PROGRESS_STATES = [
    "submitted",
    "under_review",
    "review_pending"
  ].freeze

  INVISIBLE_STATES = [
    "submitted",
    "rejected",
    "withdrawn"
  ].freeze

  default_scope  { order(:created_at => :desc) }
  scope :recent, lambda { where('created_at > ?', 1.week.ago) }
  scope :submitted, lambda { where('state = ?', 'submitted') }

  scope :since, -> (date) { where('accepted_at >= ?', date) }
  scope :in_progress, -> { where(:state => IN_PROGRESS_STATES) }
  scope :visible, -> { where(:state => VISIBLE_STATES) }
  scope :invisible, -> { where(:state => INVISIBLE_STATES) }
  scope :everything, lambda { where('state NOT IN (?)', ['rejected', 'withdrawn']) }

  before_create :set_sha, :set_last_activity
  after_create :notify_editors

  validates_presence_of :title
  validates_presence_of :repository_url, :message => "^Repository address can't be blank"
  validates_presence_of :software_version, :message => "^Version can't be blank"
  validates_presence_of :body, :message => "^Description can't be blank"
  validates :kind, inclusion: { in: Rails.application.settings["paper_types"] }, allow_nil: true

  def notify_editors
    Notifications.submission_email(self).deliver_now
  end

  def self.featured
    # TODO: Make this a thing
    Paper.first
  end

  def self.popular
    recent
  end

  def to_param
    sha
  end

  def invisible?
    INVISIBLE_STATES.include?(state)
  end

  def pretty_repository_name
    if repository_url.include?('github.com')
      name, owner = repository_url.scan(/(?<=github.com\/).*/i).first.split('/')
      return "#{name} / #{owner}"
    else
      return repository_url
    end
  end

  def pretty_doi
    return "DOI pending" unless archive_doi

    matches = archive_doi.scan(/\b(10[.][0-9]{4,}(?:[.][0-9]+)*\/(?:(?!["&\'<>])\S)+)\b/).flatten

    if matches.any?
      return matches.first
    else
      return archive_doi
    end
  end

  # Make sure that DOIs have a full http URL
  # e.g. turn 10.6084/m9.figshare.828487 into https://doi.org/10.6084/m9.figshare.828487
  def doi_with_url
    return "DOI pending" unless archive_doi

    bare_doi = archive_doi[/\b(10[.][0-9]{4,}(?:[.][0-9]+)*\/(?:(?!["&\'<>])\S)+)\b/]

    if archive_doi.include?("https://doi.org/")
      return archive_doi
    elsif bare_doi
      return "https://doi.org/#{bare_doi}"
    else
      return archive_doi
    end
  end

  def clean_archive_doi
    archive_doi.gsub(/\"/, "")
  end

  # A 5-figure integer used to produce the JOSS DOI
  def joss_id
    id = "%05d" % review_issue_id
    "#{setting(:abbreviation).downcase}.#{id}"
  end

  # Where to find the PDF for this paper
  def pdf_url
    doi_to_file = doi.gsub('/', '.')

    "#{Rails.application.settings["papers_html_url"]}/#{joss_id}/#{doi_to_file}.pdf"
  end<commit_msg>More reliable DOI links for archive<commit_after>class Paper < ActiveRecord::Base
  include SettingsHelper
  serialize :activities, Hash

  belongs_to  :submitting_author,
              :class_name => 'User',
              :validate => true,
              :foreign_key => "user_id"

  belongs_to  :editor

  include AASM

  aasm :column => :state do
    state :submitted, :initial => true
    state :review_pending
    state :under_review
    state :review_completed
    state :superceded
    state :accepted
    state :rejected
    state :withdrawn

    event :reject do
      transitions :to => :rejected
    end

    event :start_meta_review do
      transitions :from => :submitted, :to => :review_pending, :if => :create_meta_review_issue
    end

    event :start_review do
      transitions :from => :review_pending, :to => :under_review, :if => :create_review_issue
    end

    event :accept do
      transitions :to => :accepted
    end

    event :withdraw do
      transitions :to => :withdrawn
    end
  end

  VISIBLE_STATES = [
    "accepted",
    "superceded"
  ].freeze

  IN_PROGRESS_STATES = [
    "submitted",
    "under_review",
    "review_pending"
  ].freeze

  INVISIBLE_STATES = [
    "submitted",
    "rejected",
    "withdrawn"
  ].freeze

  default_scope  { order(:created_at => :desc) }
  scope :recent, lambda { where('created_at > ?', 1.week.ago) }
  scope :submitted, lambda { where('state = ?', 'submitted') }

  scope :since, -> (date) { where('accepted_at >= ?', date) }
  scope :in_progress, -> { where(:state => IN_PROGRESS_STATES) }
  scope :visible, -> { where(:state => VISIBLE_STATES) }
  scope :invisible, -> { where(:state => INVISIBLE_STATES) }
  scope :everything, lambda { where('state NOT IN (?)', ['rejected', 'withdrawn']) }

  before_create :set_sha, :set_last_activity
  after_create :notify_editors

  validates_presence_of :title
  validates_presence_of :repository_url, :message => "^Repository address can't be blank"
  validates_presence_of :software_version, :message => "^Version can't be blank"
  validates_presence_of :body, :message => "^Description can't be blank"
  validates :kind, inclusion: { in: Rails.application.settings["paper_types"] }, allow_nil: true

  def notify_editors
    Notifications.submission_email(self).deliver_now
  end

  def self.featured
    # TODO: Make this a thing
    Paper.first
  end

  def self.popular
    recent
  end

  def to_param
    sha
  end

  def invisible?
    INVISIBLE_STATES.include?(state)
  end

  def pretty_repository_name
    if repository_url.include?('github.com')
      name, owner = repository_url.scan(/(?<=github.com\/).*/i).first.split('/')
      return "#{name} / #{owner}"
    else
      return repository_url
    end
  end

  def pretty_doi
    return "DOI pending" unless archive_doi

    matches = archive_doi.scan(/\b(10[.][0-9]{4,}(?:[.][0-9]+)*\/(?:(?!["&\'<>])\S)+)\b/).flatten

    if matches.any?
      return matches.first
    else
      return archive_doi
    end
  end

  # Make sure that DOIs have a full http URL
  # e.g. turn 10.6084/m9.figshare.828487 into https://doi.org/10.6084/m9.figshare.828487
  def doi_with_url
    return "DOI pending" unless archive_doi

    bare_doi = archive_doi[/\b(10[.][0-9]{4,}(?:[.][0-9]+)*\/(?:(?!["&\'<>])\S)+)\b/]

    if archive_doi.include?("https://doi.org/")
      return archive_doi
    elsif bare_doi
      return "https://doi.org/#{bare_doi}"
    else
      return archive_doi
    end
  end

  def clean_archive_doi
    doi_with_url.gsub(/\"/, "")
  end

  # A 5-figure integer used to produce the JOSS DOI
  def joss_id
    id = "%05d" % review_issue_id
    "#{setting(:abbreviation).downcase}.#{id}"
  end

  # Where to find the PDF for this paper
  def pdf_url
    doi_to_file = doi.gsub('/', '.')

    "#{Rails.application.settings["papers_html_url"]}/#{joss_id}/#{doi_to_file}.pdf"
  end
{'fraction_non_alphanumeric': 0.13747572815533982, 'fraction_numerical': 0.011391585760517799, 'mean_word_length': 3.1183368869936032, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 61, 'https://': 6, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3262477', 'n_tokens_mistral': 2803, 'n_tokens_neox': 2633, 'n_words': 608}