ActiveVault -> ActiveStorage

Yaroslav agreed to hand over the gem name ❤️
This commit is contained in:
David Heinemeier Hansson 2017-07-06 11:33:29 +02:00
parent 5869045f2e
commit c624df326a
38 changed files with 173 additions and 180 deletions

@ -1,7 +1,7 @@
PATH PATH
remote: . remote: .
specs: specs:
activevault (0.1) activestorage (0.1)
actionpack (>= 5.1) actionpack (>= 5.1)
activejob (>= 5.1) activejob (>= 5.1)
activerecord (>= 5.1) activerecord (>= 5.1)
@ -223,7 +223,7 @@ PLATFORMS
ruby ruby
DEPENDENCIES DEPENDENCIES
activevault! activestorage!
aws-sdk aws-sdk
bundler (~> 1.15) bundler (~> 1.15)
byebug byebug

@ -19,7 +19,7 @@ user.avatar.exist? # => true
user.avatar.purge user.avatar.purge
user.avatar.exist? # => false user.avatar.exist? # => false
user.image.url(expires_in: 5.minutes) # => /rails/blobs/<encoded-key> user.avatar.url(expires_in: 5.minutes) # => /rails/blobs/<encoded-key>
class AvatarsController < ApplicationController class AvatarsController < ApplicationController
def update def update
@ -55,7 +55,7 @@ end
## Configuration ## Configuration
Add `require "active_vault"` to config/application.rb and create a `config/initializers/active_vault_sites.rb` with the following: Add `require "active_storage"` to config/application.rb and create a `config/initializers/active_storage_sites.rb` with the following:
```ruby ```ruby

@ -1,10 +1,10 @@
Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = "activevault" s.name = "activestorage"
s.version = "0.1" s.version = "0.1"
s.authors = "David Heinemeier Hansson" s.authors = "David Heinemeier Hansson"
s.email = "david@basecamp.com" s.email = "david@basecamp.com"
s.summary = "Store files in Rails applications" s.summary = "Store files in Rails applications"
s.homepage = "https://github.com/rails/activevault" s.homepage = "https://github.com/rails/activestorage"
s.license = "MIT" s.license = "MIT"
s.required_ruby_version = ">= 1.9.3" s.required_ruby_version = ">= 1.9.3"

@ -1,7 +1,7 @@
require "active_record" require "active_record"
require "active_vault/railtie" if defined?(Rails) require "active_storage/railtie" if defined?(Rails)
module ActiveVault module ActiveStorage
extend ActiveSupport::Autoload extend ActiveSupport::Autoload
autoload :Blob autoload :Blob

@ -1,10 +1,10 @@
require "active_vault/blob" require "active_storage/blob"
require "active_vault/attachment" require "active_storage/attachment"
require "action_dispatch/http/upload" require "action_dispatch/http/upload"
require "active_support/core_ext/module/delegation" require "active_support/core_ext/module/delegation"
class ActiveVault::Attached class ActiveStorage::Attached
attr_reader :name, :record attr_reader :name, :record
def initialize(name, record) def initialize(name, record)
@ -14,21 +14,21 @@ def initialize(name, record)
private private
def create_blob_from(attachable) def create_blob_from(attachable)
case attachable case attachable
when ActiveVault::Blob when ActiveStorage::Blob
attachable attachable
when ActionDispatch::Http::UploadedFile when ActionDispatch::Http::UploadedFile
ActiveVault::Blob.create_after_upload! \ ActiveStorage::Blob.create_after_upload! \
io: attachable.open, io: attachable.open,
filename: attachable.original_filename, filename: attachable.original_filename,
content_type: attachable.content_type content_type: attachable.content_type
when Hash when Hash
ActiveVault::Blob.create_after_upload!(attachable) ActiveStorage::Blob.create_after_upload!(attachable)
else else
nil nil
end end
end end
end end
require "active_vault/attached/one" require "active_storage/attached/one"
require "active_vault/attached/many" require "active_storage/attached/many"
require "active_vault/attached/macros" require "active_storage/attached/macros"

@ -0,0 +1,23 @@
module ActiveStorage::Attached::Macros
def has_one_attached(name, dependent: :purge_later)
define_method(name) do
instance_variable_get("@active_storage_attached_#{name}") ||
instance_variable_set("@active_storage_attached_#{name}", ActiveStorage::Attached::One.new(name, self))
end
if dependent == :purge_later
before_destroy { public_send(name).purge_later }
end
end
def has_many_attached(name, dependent: :purge_later)
define_method(name) do
instance_variable_get("@active_storage_attached_#{name}") ||
instance_variable_set("@active_storage_attached_#{name}", ActiveStorage::Attached::Many.new(name, self))
end
if dependent == :purge_later
before_destroy { public_send(name).purge_later }
end
end
end

@ -1,13 +1,13 @@
class ActiveVault::Attached::Many < ActiveVault::Attached class ActiveStorage::Attached::Many < ActiveStorage::Attached
delegate_missing_to :attachments delegate_missing_to :attachments
def attachments def attachments
@attachments ||= ActiveVault::Attachment.where(record_gid: record.to_gid.to_s, name: name) @attachments ||= ActiveStorage::Attachment.where(record_gid: record.to_gid.to_s, name: name)
end end
def attach(*attachables) def attach(*attachables)
@attachments = attachments | Array(attachables).flatten.collect do |attachable| @attachments = attachments | Array(attachables).flatten.collect do |attachable|
ActiveVault::Attachment.create!(record_gid: record.to_gid.to_s, name: name, blob: create_blob_from(attachable)) ActiveStorage::Attachment.create!(record_gid: record.to_gid.to_s, name: name, blob: create_blob_from(attachable))
end end
end end

@ -1,12 +1,12 @@
class ActiveVault::Attached::One < ActiveVault::Attached class ActiveStorage::Attached::One < ActiveStorage::Attached
delegate_missing_to :attachment delegate_missing_to :attachment
def attachment def attachment
@attachment ||= ActiveVault::Attachment.find_by(record_gid: record.to_gid.to_s, name: name) @attachment ||= ActiveStorage::Attachment.find_by(record_gid: record.to_gid.to_s, name: name)
end end
def attach(attachable) def attach(attachable)
@attachment = ActiveVault::Attachment.create!(record_gid: record.to_gid.to_s, name: name, blob: create_blob_from(attachable)) @attachment = ActiveStorage::Attachment.create!(record_gid: record.to_gid.to_s, name: name, blob: create_blob_from(attachable))
end end
def attached? def attached?

@ -1,12 +1,12 @@
require "active_vault/blob" require "active_storage/blob"
require "global_id" require "global_id"
require "active_support/core_ext/module/delegation" require "active_support/core_ext/module/delegation"
# Schema: id, record_gid, blob_id, created_at # Schema: id, record_gid, blob_id, created_at
class ActiveVault::Attachment < ActiveRecord::Base class ActiveStorage::Attachment < ActiveRecord::Base
self.table_name = "active_vault_attachments" self.table_name = "active_storage_attachments"
belongs_to :blob, class_name: "ActiveVault::Blob" belongs_to :blob, class_name: "ActiveStorage::Blob"
delegate_missing_to :blob delegate_missing_to :blob
@ -25,6 +25,6 @@ def purge
end end
def purge_later def purge_later
ActiveVault::PurgeJob.perform_later(self) ActiveStorage::PurgeJob.perform_later(self)
end end
end end

@ -1,10 +1,10 @@
require "active_vault/site" require "active_storage/site"
require "active_vault/filename" require "active_storage/filename"
require "active_vault/purge_job" require "active_storage/purge_job"
# Schema: id, key, filename, content_type, metadata, byte_size, checksum, created_at # Schema: id, key, filename, content_type, metadata, byte_size, checksum, created_at
class ActiveVault::Blob < ActiveRecord::Base class ActiveStorage::Blob < ActiveRecord::Base
self.table_name = "active_vault_blobs" self.table_name = "active_storage_blobs"
has_secure_token :key has_secure_token :key
store :metadata, coder: JSON store :metadata, coder: JSON
@ -33,7 +33,7 @@ def key
end end
def filename def filename
ActiveVault::Filename.new(self[:filename]) ActiveStorage::Filename.new(self[:filename])
end end
def url(expires_in: 5.minutes, disposition: :inline) def url(expires_in: 5.minutes, disposition: :inline)
@ -63,6 +63,6 @@ def purge
end end
def purge_later def purge_later
ActiveVault::PurgeJob.perform_later(self) ActiveStorage::PurgeJob.perform_later(self)
end end
end end

@ -1,13 +1,13 @@
# Configuration should be something like this: # Configuration should be something like this:
# #
# config/environments/development.rb # config/environments/development.rb
# config.active_vault.site = :local # config.active_storage.site = :local
# #
# config/environments/production.rb # config/environments/production.rb
# config.active_vault.site = :amazon # config.active_storage.site = :amazon
local: local:
site: Disk site: Disk
root: <%%= File.join(Dir.tmpdir, "active_vault") %> root: <%%= File.join(Dir.tmpdir, "active_storage") %>
amazon: amazon:
site: S3 site: S3

@ -1,13 +1,13 @@
require "action_controller" require "action_controller"
require "active_vault/blob" require "active_storage/blob"
require "active_vault/verified_key_with_expiration" require "active_storage/verified_key_with_expiration"
require "active_support/core_ext/object/inclusion" require "active_support/core_ext/object/inclusion"
class ActiveVault::DiskController < ActionController::Base class ActiveStorage::DiskController < ActionController::Base
def show def show
if key = decode_verified_key if key = decode_verified_key
blob = ActiveVault::Blob.find_by!(key: key) blob = ActiveStorage::Blob.find_by!(key: key)
if stale?(etag: blob.checksum) if stale?(etag: blob.checksum)
send_data blob.download, filename: blob.filename, type: blob.content_type, disposition: disposition_param send_data blob.download, filename: blob.filename, type: blob.content_type, disposition: disposition_param
@ -19,7 +19,7 @@ def show
private private
def decode_verified_key def decode_verified_key
ActiveVault::VerifiedKeyWithExpiration.decode(params[:encoded_key]) ActiveStorage::VerifiedKeyWithExpiration.decode(params[:encoded_key])
end end
def disposition_param def disposition_param

@ -1,4 +1,4 @@
class ActiveVault::Download class ActiveStorage::Download
# Sending .ai files as application/postscript to Safari opens them in a blank, grey screen. # Sending .ai files as application/postscript to Safari opens them in a blank, grey screen.
# Downloading .ai as application/postscript files in Safari appends .ps to the extension. # Downloading .ai as application/postscript files in Safari appends .ps to the extension.
# Sending HTML, SVG, XML and SWF files as binary closes XSS vulnerabilities. # Sending HTML, SVG, XML and SWF files as binary closes XSS vulnerabilities.

@ -1,4 +1,4 @@
class ActiveVault::Filename class ActiveStorage::Filename
include Comparable include Comparable
def initialize(filename) def initialize(filename)

@ -1,6 +1,6 @@
class ActiveVault::CreateTables < ActiveRecord::Migration[5.1] class ActiveStorage::CreateTables < ActiveRecord::Migration[5.1]
def change def change
create_table :active_vault_blobs do |t| create_table :active_storage_blobs do |t|
t.string :key t.string :key
t.string :filename t.string :filename
t.string :content_type t.string :content_type
@ -12,7 +12,7 @@ def change
t.index [ :key ], unique: true t.index [ :key ], unique: true
end end
create_table :active_vault_attachments do |t| create_table :active_storage_attachments do |t|
t.string :name t.string :name
t.string :record_gid t.string :record_gid
t.integer :blob_id t.integer :blob_id

@ -1,7 +1,7 @@
require "active_job" require "active_job"
class ActiveVault::PurgeJob < ActiveJob::Base class ActiveStorage::PurgeJob < ActiveJob::Base
# FIXME: Limit this to a custom ActiveVault error # FIXME: Limit this to a custom ActiveStorage error
retry_on StandardError retry_on StandardError
def perform(attachment_or_blob) def perform(attachment_or_blob)

@ -0,0 +1,27 @@
require "rails/railtie"
module ActiveStorage
class Railtie < Rails::Railtie # :nodoc:
config.active_storage = ActiveSupport::OrderedOptions.new
config.eager_load_namespaces << ActiveStorage
initializer "active_storage.routes" do
require "active_storage/disk_controller"
config.after_initialize do |app|
app.routes.prepend do
get "/rails/blobs/:encoded_key" => "active_storage/disk#show", as: :rails_disk_blob
end
end
end
initializer "active_storage.attached" do
require "active_storage/attached"
ActiveSupport.on_load(:active_record) do
extend ActiveStorage::Attached::Macros
end
end
end
end

@ -1,9 +1,9 @@
# Abstract class serving as an interface for concrete sites. # Abstract class serving as an interface for concrete sites.
class ActiveVault::Site class ActiveStorage::Site
def self.configure(site, **options) def self.configure(site, **options)
begin begin
require "active_vault/site/#{site.to_s.downcase}_site" require "active_storage/site/#{site.to_s.downcase}_site"
ActiveVault::Site.const_get(:"#{site}Site").new(**options) ActiveStorage::Site.const_get(:"#{site}Site").new(**options)
rescue LoadError => e rescue LoadError => e
puts "Couldn't configure site: #{site} (#{e.message})" puts "Couldn't configure site: #{site} (#{e.message})"
end end

@ -1,7 +1,7 @@
require "fileutils" require "fileutils"
require "pathname" require "pathname"
class ActiveVault::Site::DiskSite < ActiveVault::Site class ActiveStorage::Site::DiskSite < ActiveStorage::Site
attr_reader :root attr_reader :root
def initialize(root:) def initialize(root:)
@ -38,7 +38,7 @@ def exist?(key)
def url(key, expires_in:, disposition:, filename:) def url(key, expires_in:, disposition:, filename:)
verified_key_with_expiration = ActiveVault::VerifiedKeyWithExpiration.encode(key, expires_in: expires_in) verified_key_with_expiration = ActiveStorage::VerifiedKeyWithExpiration.encode(key, expires_in: expires_in)
if defined?(Rails) && defined?(Rails.application) if defined?(Rails) && defined?(Rails.application)
Rails.application.routes.url_helpers.rails_disk_blob_path(verified_key_with_expiration, disposition: disposition) Rails.application.routes.url_helpers.rails_disk_blob_path(verified_key_with_expiration, disposition: disposition)

@ -1,7 +1,7 @@
require "google/cloud/storage" require "google/cloud/storage"
require "active_support/core_ext/object/to_query" require "active_support/core_ext/object/to_query"
class ActiveVault::Site::GCSSite < ActiveVault::Site class ActiveStorage::Site::GCSSite < ActiveStorage::Site
attr_reader :client, :bucket attr_reader :client, :bucket
def initialize(project:, keyfile:, bucket:) def initialize(project:, keyfile:, bucket:)

@ -1,4 +1,4 @@
class ActiveVault::Site::MirrorSite < ActiveVault::Site class ActiveStorage::Site::MirrorSite < ActiveStorage::Site
attr_reader :sites attr_reader :sites
def initialize(sites:) def initialize(sites:)

@ -1,6 +1,6 @@
require "aws-sdk" require "aws-sdk"
class ActiveVault::Site::S3Site < ActiveVault::Site class ActiveStorage::Site::S3Site < ActiveStorage::Site
attr_reader :client, :bucket attr_reader :client, :bucket
def initialize(access_key_id:, secret_access_key:, region:, bucket:) def initialize(access_key_id:, secret_access_key:, region:, bucket:)

@ -1,5 +1,5 @@
class ActiveVault::VerifiedKeyWithExpiration class ActiveStorage::VerifiedKeyWithExpiration
class_attribute :verifier, default: defined?(Rails) ? Rails.application.message_verifier('ActiveVault') : nil class_attribute :verifier, default: defined?(Rails) ? Rails.application.message_verifier('ActiveStorage') : nil
class << self class << self
def encode(key, expires_in: nil) def encode(key, expires_in: nil)

@ -1,23 +0,0 @@
module ActiveVault::Attached::Macros
def has_one_attached(name, dependent: :purge_later)
define_method(name) do
instance_variable_get("@active_vault_attached_#{name}") ||
instance_variable_set("@active_vault_attached_#{name}", ActiveVault::Attached::One.new(name, self))
end
if dependent == :purge_later
before_destroy { public_send(name).purge_later }
end
end
def has_many_attached(name, dependent: :purge_later)
define_method(name) do
instance_variable_get("@active_vault_attached_#{name}") ||
instance_variable_set("@active_vault_attached_#{name}", ActiveVault::Attached::Many.new(name, self))
end
if dependent == :purge_later
before_destroy { public_send(name).purge_later }
end
end
end

@ -1,27 +0,0 @@
require "rails/railtie"
module ActiveVault
class Railtie < Rails::Railtie # :nodoc:
config.active_vault = ActiveSupport::OrderedOptions.new
config.eager_load_namespaces << ActiveVault
initializer "active_vault.routes" do
require "active_vault/disk_controller"
config.after_initialize do |app|
app.routes.prepend do
get "/rails/blobs/:encoded_key" => "active_vault/disk#show", as: :rails_disk_blob
end
end
end
initializer "active_vault.attached" do
require "active_vault/attached"
ActiveSupport.on_load(:active_record) do
extend ActiveVault::Attached::Macros
end
end
end
end

@ -1,6 +1,6 @@
require "test_helper" require "test_helper"
require "database/setup" require "database/setup"
require "active_vault/blob" require "active_storage/blob"
require "active_job" require "active_job"
ActiveJob::Base.queue_adapter = :test ActiveJob::Base.queue_adapter = :test
@ -13,12 +13,12 @@ class User < ActiveRecord::Base
has_many_attached :highlights has_many_attached :highlights
end end
class ActiveVault::AttachmentsTest < ActiveSupport::TestCase class ActiveStorage::AttachmentsTest < ActiveSupport::TestCase
include ActiveJob::TestHelper include ActiveJob::TestHelper
setup { @user = User.create!(name: "DHH") } setup { @user = User.create!(name: "DHH") }
teardown { ActiveVault::Blob.all.each(&:purge) } teardown { ActiveStorage::Blob.all.each(&:purge) }
test "attach existing blob" do test "attach existing blob" do
@user.avatar.attach create_blob(filename: "funky.jpg") @user.avatar.attach create_blob(filename: "funky.jpg")
@ -36,7 +36,7 @@ class ActiveVault::AttachmentsTest < ActiveSupport::TestCase
@user.avatar.purge @user.avatar.purge
assert_not @user.avatar.attached? assert_not @user.avatar.attached?
assert_not ActiveVault::Blob.site.exist?(avatar_key) assert_not ActiveStorage::Blob.site.exist?(avatar_key)
end end
test "purge attached blob later when the record is destroyed" do test "purge attached blob later when the record is destroyed" do
@ -46,8 +46,8 @@ class ActiveVault::AttachmentsTest < ActiveSupport::TestCase
perform_enqueued_jobs do perform_enqueued_jobs do
@user.destroy @user.destroy
assert_nil ActiveVault::Blob.find_by(key: avatar_key) assert_nil ActiveStorage::Blob.find_by(key: avatar_key)
assert_not ActiveVault::Blob.site.exist?(avatar_key) assert_not ActiveStorage::Blob.site.exist?(avatar_key)
end end
end end
@ -74,8 +74,8 @@ class ActiveVault::AttachmentsTest < ActiveSupport::TestCase
@user.highlights.purge @user.highlights.purge
assert_not @user.highlights.attached? assert_not @user.highlights.attached?
assert_not ActiveVault::Blob.site.exist?(highlight_keys.first) assert_not ActiveStorage::Blob.site.exist?(highlight_keys.first)
assert_not ActiveVault::Blob.site.exist?(highlight_keys.second) assert_not ActiveStorage::Blob.site.exist?(highlight_keys.second)
end end
test "purge attached blobs later when the record is destroyed" do test "purge attached blobs later when the record is destroyed" do
@ -85,11 +85,11 @@ class ActiveVault::AttachmentsTest < ActiveSupport::TestCase
perform_enqueued_jobs do perform_enqueued_jobs do
@user.destroy @user.destroy
assert_nil ActiveVault::Blob.find_by(key: highlight_keys.first) assert_nil ActiveStorage::Blob.find_by(key: highlight_keys.first)
assert_not ActiveVault::Blob.site.exist?(highlight_keys.first) assert_not ActiveStorage::Blob.site.exist?(highlight_keys.first)
assert_nil ActiveVault::Blob.find_by(key: highlight_keys.second) assert_nil ActiveStorage::Blob.find_by(key: highlight_keys.second)
assert_not ActiveVault::Blob.site.exist?(highlight_keys.second) assert_not ActiveStorage::Blob.site.exist?(highlight_keys.second)
end end
end end
end end

@ -1,8 +1,8 @@
require "test_helper" require "test_helper"
require "database/setup" require "database/setup"
require "active_vault/blob" require "active_storage/blob"
class ActiveVault::BlobTest < ActiveSupport::TestCase class ActiveStorage::BlobTest < ActiveSupport::TestCase
test "create after upload sets byte size and checksum" do test "create after upload sets byte size and checksum" do
data = "Hello world!" data = "Hello world!"
blob = create_blob data: data blob = create_blob data: data
@ -23,6 +23,6 @@ class ActiveVault::BlobTest < ActiveSupport::TestCase
private private
def expected_url_for(blob, disposition: :inline) def expected_url_for(blob, disposition: :inline)
"/rails/blobs/#{ActiveVault::VerifiedKeyWithExpiration.encode(blob.key, expires_in: 5.minutes)}?disposition=#{disposition}" "/rails/blobs/#{ActiveStorage::VerifiedKeyWithExpiration.encode(blob.key, expires_in: 5.minutes)}?disposition=#{disposition}"
end end
end end

@ -1,4 +1,4 @@
class ActiveVault::CreateUsers < ActiveRecord::Migration[5.1] class ActiveStorage::CreateUsers < ActiveRecord::Migration[5.1]
def change def change
create_table :users do |t| create_table :users do |t|
t.string :name t.string :name

@ -1,6 +1,6 @@
require "active_vault/migration" require "active_storage/migration"
require_relative "create_users_migration" require_relative "create_users_migration"
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:') ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveVault::CreateTables.migrate(:up) ActiveStorage::CreateTables.migrate(:up)
ActiveVault::CreateUsers.migrate(:up) ActiveStorage::CreateUsers.migrate(:up)

@ -4,30 +4,30 @@
require "action_controller" require "action_controller"
require "action_controller/test_case" require "action_controller/test_case"
require "active_vault/disk_controller" require "active_storage/disk_controller"
require "active_vault/verified_key_with_expiration" require "active_storage/verified_key_with_expiration"
class ActiveVault::DiskControllerTest < ActionController::TestCase class ActiveStorage::DiskControllerTest < ActionController::TestCase
Routes = ActionDispatch::Routing::RouteSet.new.tap do |routes| Routes = ActionDispatch::Routing::RouteSet.new.tap do |routes|
routes.draw do routes.draw do
get "/rails/blobs/:encoded_key" => "active_vault/disk#show", as: :rails_disk_blob get "/rails/blobs/:encoded_key" => "active_storage/disk#show", as: :rails_disk_blob
end end
end end
setup do setup do
@blob = create_blob @blob = create_blob
@routes = Routes @routes = Routes
@controller = ActiveVault::DiskController.new @controller = ActiveStorage::DiskController.new
end end
test "showing blob inline" do test "showing blob inline" do
get :show, params: { encoded_key: ActiveVault::VerifiedKeyWithExpiration.encode(@blob.key, expires_in: 5.minutes) } get :show, params: { encoded_key: ActiveStorage::VerifiedKeyWithExpiration.encode(@blob.key, expires_in: 5.minutes) }
assert_equal "inline; filename=\"#{@blob.filename}\"", @response.headers["Content-Disposition"] assert_equal "inline; filename=\"#{@blob.filename}\"", @response.headers["Content-Disposition"]
assert_equal "text/plain", @response.headers["Content-Type"] assert_equal "text/plain", @response.headers["Content-Type"]
end end
test "sending blob as attachment" do test "sending blob as attachment" do
get :show, params: { encoded_key: ActiveVault::VerifiedKeyWithExpiration.encode(@blob.key, expires_in: 5.minutes), disposition: :attachment } get :show, params: { encoded_key: ActiveStorage::VerifiedKeyWithExpiration.encode(@blob.key, expires_in: 5.minutes), disposition: :attachment }
assert_equal "attachment; filename=\"#{@blob.filename}\"", @response.headers["Content-Disposition"] assert_equal "attachment; filename=\"#{@blob.filename}\"", @response.headers["Content-Disposition"]
assert_equal "text/plain", @response.headers["Content-Type"] assert_equal "text/plain", @response.headers["Content-Type"]
end end

@ -1,9 +1,9 @@
require "test_helper" require "test_helper"
class ActiveVault::FilenameTest < ActiveSupport::TestCase class ActiveStorage::FilenameTest < ActiveSupport::TestCase
test "sanitize" do test "sanitize" do
"%$|:;/\t\r\n\\".each_char do |character| "%$|:;/\t\r\n\\".each_char do |character|
filename = ActiveVault::Filename.new("foo#{character}bar.pdf") filename = ActiveStorage::Filename.new("foo#{character}bar.pdf")
assert_equal 'foo-bar.pdf', filename.sanitized assert_equal 'foo-bar.pdf', filename.sanitized
assert_equal 'foo-bar.pdf', filename.to_s assert_equal 'foo-bar.pdf', filename.to_s
end end
@ -16,21 +16,21 @@ class ActiveVault::FilenameTest < ActiveSupport::TestCase
"\xCF" => "<EFBFBD>", "\xCF" => "<EFBFBD>",
"\x00" => "", "\x00" => "",
}.each do |actual, expected| }.each do |actual, expected|
assert_equal expected, ActiveVault::Filename.new(actual).sanitized assert_equal expected, ActiveStorage::Filename.new(actual).sanitized
end end
end end
test "strips RTL override chars used to spoof unsafe executables as docs" do test "strips RTL override chars used to spoof unsafe executables as docs" do
# Would be displayed in Windows as "evilexe.pdf" due to the right-to-left # Would be displayed in Windows as "evilexe.pdf" due to the right-to-left
# (RTL) override char! # (RTL) override char!
assert_equal 'evil-fdp.exe', ActiveVault::Filename.new("evil\u{202E}fdp.exe").sanitized assert_equal 'evil-fdp.exe', ActiveStorage::Filename.new("evil\u{202E}fdp.exe").sanitized
end end
test "compare case-insensitively" do test "compare case-insensitively" do
assert_operator ActiveVault::Filename.new('foobar.pdf'), :==, ActiveVault::Filename.new('FooBar.PDF') assert_operator ActiveStorage::Filename.new('foobar.pdf'), :==, ActiveStorage::Filename.new('FooBar.PDF')
end end
test "compare sanitized" do test "compare sanitized" do
assert_operator ActiveVault::Filename.new('foo-bar.pdf'), :==, ActiveVault::Filename.new("foo\tbar.pdf") assert_operator ActiveStorage::Filename.new('foo-bar.pdf'), :==, ActiveStorage::Filename.new("foo\tbar.pdf")
end end
end end

@ -1,8 +1,8 @@
require "tmpdir" require "tmpdir"
require "site/shared_site_tests" require "site/shared_site_tests"
class ActiveVault::Site::DiskSiteTest < ActiveSupport::TestCase class ActiveStorage::Site::DiskSiteTest < ActiveSupport::TestCase
SITE = ActiveVault::Site.configure(:Disk, root: File.join(Dir.tmpdir, "active_vault")) SITE = ActiveStorage::Site.configure(:Disk, root: File.join(Dir.tmpdir, "active_storage"))
include ActiveVault::Site::SharedSiteTests include ActiveStorage::Site::SharedSiteTests
end end

@ -1,10 +1,10 @@
require "site/shared_site_tests" require "site/shared_site_tests"
if SITE_CONFIGURATIONS[:gcs] if SITE_CONFIGURATIONS[:gcs]
class ActiveVault::Site::GCSSiteTest < ActiveSupport::TestCase class ActiveStorage::Site::GCSSiteTest < ActiveSupport::TestCase
SITE = ActiveVault::Site.configure(:GCS, SITE_CONFIGURATIONS[:gcs]) SITE = ActiveStorage::Site.configure(:GCS, SITE_CONFIGURATIONS[:gcs])
include ActiveVault::Site::SharedSiteTests include ActiveStorage::Site::SharedSiteTests
test "signed URL generation" do test "signed URL generation" do
travel_to Time.now do travel_to Time.now do

@ -1,15 +1,15 @@
require "tmpdir" require "tmpdir"
require "site/shared_site_tests" require "site/shared_site_tests"
class ActiveVault::Site::MirrorSiteTest < ActiveSupport::TestCase class ActiveStorage::Site::MirrorSiteTest < ActiveSupport::TestCase
PRIMARY_DISK_SITE = ActiveVault::Site.configure(:Disk, root: File.join(Dir.tmpdir, "active_vault")) PRIMARY_DISK_SITE = ActiveStorage::Site.configure(:Disk, root: File.join(Dir.tmpdir, "active_storage"))
SECONDARY_DISK_SITE = ActiveVault::Site.configure(:Disk, root: File.join(Dir.tmpdir, "active_vault_mirror")) SECONDARY_DISK_SITE = ActiveStorage::Site.configure(:Disk, root: File.join(Dir.tmpdir, "active_storage_mirror"))
SITE = ActiveVault::Site.configure :Mirror, sites: [ PRIMARY_DISK_SITE, SECONDARY_DISK_SITE ] SITE = ActiveStorage::Site.configure :Mirror, sites: [ PRIMARY_DISK_SITE, SECONDARY_DISK_SITE ]
include ActiveVault::Site::SharedSiteTests include ActiveStorage::Site::SharedSiteTests
test "uploading to all sites" do test "uploading was done to all sites" do
begin begin
key = SecureRandom.base58(24) key = SecureRandom.base58(24)
data = "Something else entirely!" data = "Something else entirely!"
@ -27,11 +27,4 @@ class ActiveVault::Site::MirrorSiteTest < ActiveSupport::TestCase
assert PRIMARY_DISK_SITE.exist?(FIXTURE_KEY) assert PRIMARY_DISK_SITE.exist?(FIXTURE_KEY)
assert SECONDARY_DISK_SITE.exist?(FIXTURE_KEY) assert SECONDARY_DISK_SITE.exist?(FIXTURE_KEY)
end end
test "URL generation for primary site" do
travel_to Time.now do
assert_equal PRIMARY_DISK_SITE.url(FIXTURE_KEY, expires_in: 5.minutes, disposition: :inline, filename: "test.txt"),
SITE.url(FIXTURE_KEY, expires_in: 5.minutes, disposition: :inline, filename: "test.txt")
end
end
end end

@ -1,10 +1,10 @@
require "site/shared_site_tests" require "site/shared_site_tests"
if SITE_CONFIGURATIONS[:s3] if SITE_CONFIGURATIONS[:s3]
class ActiveVault::Site::S3SiteTest < ActiveSupport::TestCase class ActiveStorage::Site::S3SiteTest < ActiveSupport::TestCase
SITE = ActiveVault::Site.configure(:S3, SITE_CONFIGURATIONS[:s3]) SITE = ActiveStorage::Site.configure(:S3, SITE_CONFIGURATIONS[:s3])
include ActiveVault::Site::SharedSiteTests include ActiveStorage::Site::SharedSiteTests
end end
else else
puts "Skipping S3 Site tests because no S3 configuration was supplied" puts "Skipping S3 Site tests because no S3 configuration was supplied"

@ -8,7 +8,7 @@
puts "Missing site configuration file in test/sites/configurations.yml" puts "Missing site configuration file in test/sites/configurations.yml"
end end
module ActiveVault::Site::SharedSiteTests module ActiveStorage::Site::SharedSiteTests
extend ActiveSupport::Concern extend ActiveSupport::Concern
FIXTURE_KEY = SecureRandom.base58(24) FIXTURE_KEY = SecureRandom.base58(24)

@ -4,25 +4,25 @@
require "active_support/testing/autorun" require "active_support/testing/autorun"
require "byebug" require "byebug"
require "active_vault" require "active_storage"
require "active_vault/site" require "active_storage/site"
ActiveVault::Blob.site = ActiveVault::Site.configure(:Disk, root: File.join(Dir.tmpdir, "active_vault")) ActiveStorage::Blob.site = ActiveStorage::Site.configure(:Disk, root: File.join(Dir.tmpdir, "active_storage"))
require "active_vault/verified_key_with_expiration" require "active_storage/verified_key_with_expiration"
ActiveVault::VerifiedKeyWithExpiration.verifier = ActiveSupport::MessageVerifier.new("Testing") ActiveStorage::VerifiedKeyWithExpiration.verifier = ActiveSupport::MessageVerifier.new("Testing")
class ActiveSupport::TestCase class ActiveSupport::TestCase
private private
def create_blob(data: "Hello world!", filename: "hello.txt", content_type: "text/plain") def create_blob(data: "Hello world!", filename: "hello.txt", content_type: "text/plain")
ActiveVault::Blob.create_after_upload! io: StringIO.new(data), filename: filename, content_type: content_type ActiveStorage::Blob.create_after_upload! io: StringIO.new(data), filename: filename, content_type: content_type
end end
end end
require "active_vault/attached" require "active_storage/attached"
ActiveRecord::Base.send :extend, ActiveVault::Attached::Macros ActiveRecord::Base.send :extend, ActiveStorage::Attached::Macros
require "global_id" require "global_id"
GlobalID.app = "ActiveVaultExampleApp" GlobalID.app = "ActiveStorageExampleApp"
ActiveRecord::Base.send :include, GlobalID::Identification ActiveRecord::Base.send :include, GlobalID::Identification

@ -1,19 +1,19 @@
require "test_helper" require "test_helper"
require "active_support/core_ext/securerandom" require "active_support/core_ext/securerandom"
class ActiveVault::VerifiedKeyWithExpirationTest < ActiveSupport::TestCase class ActiveStorage::VerifiedKeyWithExpirationTest < ActiveSupport::TestCase
FIXTURE_KEY = SecureRandom.base58(24) FIXTURE_KEY = SecureRandom.base58(24)
test "without expiration" do test "without expiration" do
encoded_key = ActiveVault::VerifiedKeyWithExpiration.encode(FIXTURE_KEY) encoded_key = ActiveStorage::VerifiedKeyWithExpiration.encode(FIXTURE_KEY)
assert_equal FIXTURE_KEY, ActiveVault::VerifiedKeyWithExpiration.decode(encoded_key) assert_equal FIXTURE_KEY, ActiveStorage::VerifiedKeyWithExpiration.decode(encoded_key)
end end
test "with expiration" do test "with expiration" do
encoded_key = ActiveVault::VerifiedKeyWithExpiration.encode(FIXTURE_KEY, expires_in: 1.minute) encoded_key = ActiveStorage::VerifiedKeyWithExpiration.encode(FIXTURE_KEY, expires_in: 1.minute)
assert_equal FIXTURE_KEY, ActiveVault::VerifiedKeyWithExpiration.decode(encoded_key) assert_equal FIXTURE_KEY, ActiveStorage::VerifiedKeyWithExpiration.decode(encoded_key)
travel 2.minutes travel 2.minutes
assert_nil ActiveVault::VerifiedKeyWithExpiration.decode(encoded_key) assert_nil ActiveStorage::VerifiedKeyWithExpiration.decode(encoded_key)
end end
end end