From 1966c188cfb06b39a47082e2f6c6e33a43668ae5 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 11 Jul 2017 18:53:17 +0200 Subject: Very incomplete first stab --- .../controllers/variants_controller.rb | 22 ++++++++ lib/active_storage/engine.rb | 59 +++++++++++++--------- lib/active_storage/routes.rb | 1 + lib/active_storage/variant.rb | 52 +++++++++++++++++++ lib/active_storage/verified_key_with_expiration.rb | 2 +- 5 files changed, 112 insertions(+), 24 deletions(-) create mode 100644 lib/active_storage/controllers/variants_controller.rb create mode 100644 lib/active_storage/variant.rb (limited to 'lib/active_storage') diff --git a/lib/active_storage/controllers/variants_controller.rb b/lib/active_storage/controllers/variants_controller.rb new file mode 100644 index 0000000000..24cee16e80 --- /dev/null +++ b/lib/active_storage/controllers/variants_controller.rb @@ -0,0 +1,22 @@ +require "action_controller" +require "active_storage/blob" + +class ActiveStorage::Controllers::VariantsController < ActionController::Base + def show + if blob_key = decode_verified_key + variant = ActiveStorage::Variant.lookup(blob_key: blob_key, variation_key: params[:variation_key]) + redirect_to variant.url + else + head :not_found + end + end + + private + def decode_verified_key + ActiveStorage::VerifiedKeyWithExpiration.decode(params[:encoded_key]) + end + + def disposition_param + params[:disposition].presence_in(%w( inline attachment )) || 'inline' + end +end diff --git a/lib/active_storage/engine.rb b/lib/active_storage/engine.rb index c251f522c6..8918b179e0 100644 --- a/lib/active_storage/engine.rb +++ b/lib/active_storage/engine.rb @@ -33,29 +33,42 @@ module ActiveStorage end end - config.after_initialize do |app| - if config_choice = app.config.active_storage.service - config_file = Pathname.new(Rails.root.join("config/storage_services.yml")) - raise("Couldn't find Active Storage configuration in #{config_file}") unless config_file.exist? - - require "yaml" - require "erb" - - configs = - begin - YAML.load(ERB.new(config_file.read).result) || {} - rescue Psych::SyntaxError => e - raise "YAML syntax error occurred while parsing #{config_file}. " \ - "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \ - "Error: #{e.message}" - end - - ActiveStorage::Blob.service = - begin - ActiveStorage::Service.configure config_choice, configs - rescue => e - raise e, "Cannot load `Rails.config.active_storage.service`:\n#{e.message}", e.backtrace - end + initializer "active_storage.verifiers" do + require "active_storage/verified_key_with_expiration" + require "active_storage/variant" + + config.after_initialize do |app| + ActiveStorage::VerifiedKeyWithExpiration.verifier = \ + ActiveStorage::Variant.verifier = \ + Rails.application.message_verifier('ActiveStorage') + end + end + + initializer "active_storage.services" do + config.after_initialize do |app| + if config_choice = app.config.active_storage.service + config_file = Pathname.new(Rails.root.join("config/storage_services.yml")) + raise("Couldn't find Active Storage configuration in #{config_file}") unless config_file.exist? + + require "yaml" + require "erb" + + configs = + begin + YAML.load(ERB.new(config_file.read).result) || {} + rescue Psych::SyntaxError => e + raise "YAML syntax error occurred while parsing #{config_file}. " \ + "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \ + "Error: #{e.message}" + end + + ActiveStorage::Blob.service = + begin + ActiveStorage::Service.configure config_choice, configs + rescue => e + raise e, "Cannot load `Rails.config.active_storage.service`:\n#{e.message}", e.backtrace + end + end end end end diff --git a/lib/active_storage/routes.rb b/lib/active_storage/routes.rb index 748427a776..fade234ad3 100644 --- a/lib/active_storage/routes.rb +++ b/lib/active_storage/routes.rb @@ -1,2 +1,3 @@ get "/rails/active_storage/disk/:encoded_key/*filename" => "active_storage/disk#show", as: :rails_disk_blob +get "/rails/active_storage/variants/:encoded_key/:encoded_transformation/*filename" => "active_storage/controllers/variants#show", as: :rails_blob_variant post "/rails/active_storage/direct_uploads" => "active_storage/direct_uploads#create", as: :rails_direct_uploads diff --git a/lib/active_storage/variant.rb b/lib/active_storage/variant.rb new file mode 100644 index 0000000000..9b9dad43da --- /dev/null +++ b/lib/active_storage/variant.rb @@ -0,0 +1,52 @@ +require "active_storage/blob" +require "mini_magick" + +class ActiveStorage::Variant + class_attribute :verifier + + attr_reader :blob, :variation + delegate :service, to: :blob + + def self.lookup(blob_key:, variation_key:) + new ActiveStorage::Blob.find_by!(key: blob_key), variation: verifier.verify(variation_key) + end + + def self.encode_key(variation) + verifier.generate(variation) + end + + def initialize(blob, variation:) + @blob, @variation = blob, variation + end + + def url(expires_in: 5.minutes, disposition: :inline) + perform unless exist? + service.url key, expires_in: expires_in, disposition: disposition, filename: blob.filename + end + + def key + verifier.generate(variation) + end + + private + def perform + upload_variant transform(download_blob) + end + + def download_blob + service.download(blob.key) + end + + def upload_variant(variation) + service.upload key, variation + end + + def transform(io) + # FIXME: Actually do a variant based on the variation + File.open MiniMagick::Image.read(io).resize("500x500").path + end + + def exist? + service.exist?(key) + end +end diff --git a/lib/active_storage/verified_key_with_expiration.rb b/lib/active_storage/verified_key_with_expiration.rb index 8708106735..4a46483db5 100644 --- a/lib/active_storage/verified_key_with_expiration.rb +++ b/lib/active_storage/verified_key_with_expiration.rb @@ -1,5 +1,5 @@ class ActiveStorage::VerifiedKeyWithExpiration - class_attribute :verifier, default: defined?(Rails) ? Rails.application.message_verifier('ActiveStorage') : nil + class_attribute :verifier class << self def encode(key, expires_in: nil) -- cgit v1.2.3