cdn/app/models/upload.rb
2026-01-29 16:24:14 -05:00

90 lines
2.1 KiB
Ruby

# frozen_string_literal: true
require 'open-uri'
class Upload < ApplicationRecord
include PgSearch::Model
# UUID v7 primary key (automatic via migration)
belongs_to :user
belongs_to :blob, class_name: 'ActiveStorage::Blob'
after_destroy :purge_blob
# Delegate file metadata to blob (no duplication!)
delegate :filename, :byte_size, :content_type, :checksum, to: :blob
# Search configuration
pg_search_scope :search_by_filename,
associated_against: {
blob: :filename
},
using: {
tsearch: { prefix: true }
}
pg_search_scope :search,
against: [:original_url],
associated_against: {
blob: :filename,
user: [:email, :name]
},
using: { tsearch: { prefix: true } }
# Aliases for consistency
alias_method :file_size, :byte_size
alias_method :mime_type, :content_type
# Provenance enum
enum :provenance, {
slack: 'slack',
web: 'web',
api: 'api',
rescued: 'rescued'
}, validate: true
validates :provenance, presence: true
scope :recent, -> { order(created_at: :desc) }
scope :by_user, ->(user) { where(user: user) }
scope :today, -> { where('created_at >= ?', Time.zone.now.beginning_of_day) }
scope :this_week, -> { where('created_at >= ?', Time.zone.now.beginning_of_week) }
scope :this_month, -> { where('created_at >= ?', Time.zone.now.beginning_of_month) }
def human_file_size
ActiveSupport::NumberHelper.number_to_human_size(byte_size)
end
# Get CDN URL (uses external uploads controller)
def cdn_url
Rails.application.routes.url_helpers.external_upload_url(
id:,
filename:,
host: ENV['CDN_HOST'] || 'cdn.hackclub.com'
)
end
# Create upload from URL (for API/rescue operations)
def self.create_from_url(url, user:, provenance:, original_url: nil)
downloaded = URI.open(url)
blob = ActiveStorage::Blob.create_and_upload!(
io: downloaded,
filename: File.basename(URI.parse(url).path)
)
create!(
user: user,
blob: blob,
provenance: provenance,
original_url: original_url
)
end
private
def purge_blob
blob.purge
end
end