view app/models/paste.rb @ 499:d2ef59c9a4b4

Use rails rubocop
author nanaya <me@nanaya.net>
date Sun, 15 Dec 2024 22:33:27 +0900
parents 84ca55a0568e
children
line wrap: on
line source

class Paste < ApplicationRecord
  attr_accessor :is_private
  after_initialize :set_privacy, if: :new_record?

  before_validation :paste_limit
  before_validation :convert_newlines
  before_validation :set_paste_hash
  before_validation :set_paste_key
  before_validation :set_paste_secret
  validates :paste, :paste_hash, :key, :ip, presence: true
  validates :paste, length: { maximum: 1_000_000 }

  def to_param
    path
  end

  def self.safe_find(raw_id)
    /\A(?<id>[0-9]+)(?:-(?<secret>[0-9a-f]+))?\z/i =~ raw_id.to_s

    find_by(secret: secret.try(:downcase), id: id)
  end

  def self.graceful_create(params)
    paste = new(params)
    fresh = true
    created = true

    begin
      created = paste.save
    rescue ActiveRecord::RecordNotUnique
      paste = find_by(ip: paste.ip, paste_hash: paste.paste_hash)
      fresh = false
    end

    [ created, paste, fresh ]
  end

  def paste_gzip=(paste)
    paste = paste.read if paste.is_a? ActionDispatch::Http::UploadedFile

    self.paste = ActiveSupport::Gzip.decompress paste
  end

  def paste_gzip_base64=(paste)
    self.paste_gzip = Base64.decode64(paste)
  end

  def safe_destroy(param_key)
    if key == param_key
      destroy
    else
      errors.add(:key, "is invalid")
      false
    end
  end

  def path
    [ id, secret.presence ].compact.join("-")
  end

  def set_paste_hash
    self.paste_hash = Digest::SHA512.hexdigest("#{paste}\n")
  end

  def set_paste_key
    self.key ||= SecureRandom.hex(4)
  end

  def set_paste_secret
    self.secret = SecureRandom.hex(4) if is_private?
  end

  def is_private?
    is_private == "1"
  end

  def convert_newlines
    self.paste = paste.to_s.gsub("\r\n", "\n").tr("\r", "\n")
  end

  def paste_limit
    ip_post_recent_count = self.class.where(ip: ip).where("created_at > ?", Time.zone.now - 1.hour).count
    errors.add :base, :limit if ip_post_recent_count > 100
  end

  def set_privacy
    self.is_private ||= "0"
  end

  def self.fix_all
    stats = Hash.new(0)
    all.find_each do |p|
      p.save
      stats[:count] += 1
      stats[:private] += 1 if p.secret
    end
    stats
  end
end