X-Git-Url: https://projects.mako.cc/source/selectricity-live/blobdiff_plain/a38724bea6c09b479a93948b6ef4ef61edd24f39..e75d29998f5348be83dde4b6fd8f5aa437c2dc74:/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/backends/s3_backend.rb diff --git a/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/backends/s3_backend.rb b/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/backends/s3_backend.rb index b81fbde..53b0caf 100644 --- a/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/backends/s3_backend.rb +++ b/vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/backends/s3_backend.rb @@ -17,22 +17,28 @@ module Technoweenie # :nodoc: # If you don't already have your access keys, all you need to sign up for the S3 service is an account at Amazon. # You can sign up for S3 and get access keys by visiting http://aws.amazon.com/s3. # + # If you wish to use Amazon CloudFront to serve the files, you can also specify a distibution domain for the bucket. + # To read more about CloudFront, visit http://aws.amazon.com/cloudfront + # # Example configuration (RAILS_ROOT/config/amazon_s3.yml) - # + # # development: # bucket_name: appname_development # access_key_id: # secret_access_key: - # + # distribution_domain: XXXX.cloudfront.net + # # test: # bucket_name: appname_test # access_key_id: # secret_access_key: - # + # distribution_domain: XXXX.cloudfront.net + # # production: # bucket_name: appname # access_key_id: # secret_access_key: + # distribution_domain: XXXX.cloudfront.net # # You can change the location of the config path by passing a full path to the :s3_config_path option. # @@ -59,6 +65,8 @@ module Technoweenie # :nodoc: # * :server - The server to make requests to. Defaults to s3.amazonaws.com. # * :port - The port to the requests should be made on. Defaults to 80 or 443 if :use_ssl is set. # * :use_ssl - If set to true, :port will be implicitly set to 443, unless specified otherwise. Defaults to false. + # * :distribution_domain - The CloudFront distribution domain for the bucket. This can either be the assigned + # distribution domain (ie. XXX.cloudfront.net) or a chosen domain using a CNAME. See CloudFront for more details. # # == Usage # @@ -81,10 +89,43 @@ module Technoweenie # :nodoc: # # Which would result in URLs like http(s)://:server/:bucket_name/my/custom/path/:id/:filename. # + # === Using different bucket names on different models + # + # By default the bucket name that the file will be stored to is the one specified by the + # :bucket_name key in the amazon_s3.yml file. You can use the :bucket_key option + # to overide this behavior on a per model basis. For instance if you want a bucket that will hold + # only Photos you can do this: + # + # class Photo < ActiveRecord::Base + # has_attachment :storage => :s3, :bucket_key => :photo_bucket_name + # end + # + # And then your amazon_s3.yml file needs to look like this. + # + # development: + # bucket_name: appname_development + # access_key_id: + # secret_access_key: + # + # test: + # bucket_name: appname_test + # access_key_id: + # secret_access_key: + # + # production: + # bucket_name: appname + # photo_bucket_name: appname_photos + # access_key_id: + # secret_access_key: + # + # If the bucket_key you specify is not there in a certain environment then attachment_fu will + # default to the bucket_name key. This way you only have to create special buckets + # this can be helpful if you only need special buckets in certain environments. + # # === Permissions # # By default, files are stored on S3 with public access permissions. You can customize this using - # the :s3_access option to has_attachment. Available values are + # the :s3_access option to has_attachment. Available values are # :private, :public_read_write, and :authenticated_read. # # === Other options @@ -117,13 +158,23 @@ module Technoweenie # :nodoc: # # Niether base_path or full_filename include the bucket name as part of the path. # You can retrieve the bucket name using the bucket_name method. + # + # === Accessing CloudFront URLs + # + # You can get an object's CloudFront URL using the cloudfront_url accessor. Using the example from above: + # @postcard.cloudfront_url # => http://XXXX.cloudfront.net/photos/1/mexico.jpg + # + # The resulting url is in the form: http://:distribution_domain/:table_name/:id/:file + # + # If you set :cloudfront to true in your model, the public_filename will be the CloudFront + # URL, not the S3 URL. module S3Backend class RequiredLibraryNotFoundError < StandardError; end class ConfigFileNotFoundError < StandardError; end def self.included(base) #:nodoc: mattr_reader :bucket_name, :s3_config - + begin require 'aws/s3' include AWS::S3 @@ -133,20 +184,21 @@ module Technoweenie # :nodoc: begin @@s3_config_path = base.attachment_options[:s3_config_path] || (RAILS_ROOT + '/config/amazon_s3.yml') - @@s3_config = @@s3_config = YAML.load_file(@@s3_config_path)[RAILS_ENV].symbolize_keys + @@s3_config = @@s3_config = YAML.load(ERB.new(File.read(@@s3_config_path)).result)[RAILS_ENV].symbolize_keys #rescue # raise ConfigFileNotFoundError.new('File %s not found' % @@s3_config_path) end - @@bucket_name = s3_config[:bucket_name] + bucket_key = base.attachment_options[:bucket_key] + + if bucket_key and s3_config[bucket_key.to_sym] + eval_string = "def bucket_name()\n \"#{s3_config[bucket_key.to_sym]}\"\nend" + else + eval_string = "def bucket_name()\n \"#{s3_config[:bucket_name]}\"\nend" + end + base.class_eval(eval_string, __FILE__, __LINE__) - Base.establish_connection!( - :access_key_id => s3_config[:access_key_id], - :secret_access_key => s3_config[:secret_access_key], - :server => s3_config[:server], - :port => s3_config[:port], - :use_ssl => s3_config[:use_ssl] - ) + Base.establish_connection!(s3_config.slice(:access_key_id, :secret_access_key, :server, :port, :use_ssl, :persistent, :proxy)) # Bucket.create(@@bucket_name) @@ -156,27 +208,35 @@ module Technoweenie # :nodoc: def self.protocol @protocol ||= s3_config[:use_ssl] ? 'https://' : 'http://' end - + def self.hostname @hostname ||= s3_config[:server] || AWS::S3::DEFAULT_HOST end - + def self.port_string - @port_string ||= s3_config[:port] == (s3_config[:use_ssl] ? 443 : 80) ? '' : ":#{s3_config[:port]}" + @port_string ||= (s3_config[:port].nil? || s3_config[:port] == (s3_config[:use_ssl] ? 443 : 80)) ? '' : ":#{s3_config[:port]}" + end + + def self.distribution_domain + @distribution_domain = s3_config[:distribution_domain] end module ClassMethods def s3_protocol Technoweenie::AttachmentFu::Backends::S3Backend.protocol end - + def s3_hostname Technoweenie::AttachmentFu::Backends::S3Backend.hostname end - + def s3_port_string Technoweenie::AttachmentFu::Backends::S3Backend.port_string end + + def cloudfront_distribution_domain + Technoweenie::AttachmentFu::Backends::S3Backend.distribution_domain + end end # Overwrites the base filename writer in order to store the old filename @@ -202,7 +262,7 @@ module Technoweenie # :nodoc: File.join(base_path, thumbnail_name_for(thumbnail)) end - # All public objects are accessible via a GET request to the S3 servers. You can generate a + # All public objects are accessible via a GET request to the S3 servers. You can generate a # url for an object using the s3_url method. # # @photo.s3_url @@ -215,9 +275,29 @@ module Technoweenie # :nodoc: def s3_url(thumbnail = nil) File.join(s3_protocol + s3_hostname + s3_port_string, bucket_name, full_filename(thumbnail)) end - alias :public_filename :s3_url + + # All public objects are accessible via a GET request to CloudFront. You can generate a + # url for an object using the cloudfront_url method. + # + # @photo.cloudfront_url + # + # The resulting url is in the form: http://:distribution_domain/:table_name/:id/:file using + # the :distribution_domain variable set in the configuration parameters in RAILS_ROOT/config/amazon_s3.yml. + # + # The optional thumbnail argument will output the thumbnail's filename (if any). + def cloudfront_url(thumbnail = nil) + "http://" + cloudfront_distribution_domain + "/" + full_filename(thumbnail) + end + + def public_filename(*args) + if attachment_options[:cloudfront] + cloudfront_url(args) + else + s3_url(args) + end + end - # All private objects are accessible via an authenticated GET request to the S3 servers. You can generate an + # All private objects are accessible via an authenticated GET request to the S3 servers. You can generate an # authenticated url for an object like this: # # @photo.authenticated_s3_url @@ -229,7 +309,7 @@ module Technoweenie # :nodoc: # # # Absolute expiration date (October 13th, 2025) # @photo.authenticated_s3_url(:expires => Time.mktime(2025,10,13).to_i) - # + # # # Expiration in five hours from now # @photo.authenticated_s3_url(:expires_in => 5.hours) # @@ -242,8 +322,9 @@ module Technoweenie # :nodoc: # # @photo.authenticated_s3_url('thumbnail', :expires_in => 5.hours, :use_ssl => true) def authenticated_s3_url(*args) - thumbnail = args.first.is_a?(String) ? args.first : nil - options = args.last.is_a?(Hash) ? args.last : {} + options = args.extract_options! + options[:expires_in] = options[:expires_in].to_i if options[:expires_in] + thumbnail = args.shift S3Object.url_for(full_filename(thumbnail), bucket_name, options) end @@ -258,14 +339,18 @@ module Technoweenie # :nodoc: def s3_protocol Technoweenie::AttachmentFu::Backends::S3Backend.protocol end - + def s3_hostname Technoweenie::AttachmentFu::Backends::S3Backend.hostname end - + def s3_port_string Technoweenie::AttachmentFu::Backends::S3Backend.port_string end + + def cloudfront_distribution_domain + Technoweenie::AttachmentFu::Backends::S3Backend.distribution_domain + end protected # Called in the after_destroy callback @@ -275,7 +360,7 @@ module Technoweenie # :nodoc: def rename_file return unless @old_filename && @old_filename != filename - + old_full_filename = File.join(base_path, @old_filename) S3Object.rename( @@ -306,4 +391,4 @@ module Technoweenie # :nodoc: end end end -end \ No newline at end of file +end