Permalink
Browse files

Merge pull request #72 from mitfik/master

Add sync acl
  • Loading branch information...
2 parents 98ade8e + 6e1e359 commit a1466c377bb30c57d0e5fe6521a53809078ef5b2 @qoobaa committed Nov 19, 2012
Showing with 98 additions and 7 deletions.
  1. +13 −0 README.rdoc
  2. +32 −3 lib/s3/bucket.rb
  3. +1 −1 lib/s3/connection.rb
  4. +14 −3 lib/s3/object.rb
  5. +38 −0 lib/s3/parser.rb
View
13 README.rdoc
@@ -72,11 +72,24 @@ It supports both: European and US buckets through the {REST API}[http://docs.ama
Please note that new objects are created with "public-read" ACL by
default.
+=== Fetch ACL
+
+ object = bucket.objects.find('lenna.png')
+ object.request_acl # or bucket.request_acl
+
+This will return hash with all users/groups and theirs permissions
+
=== Modify ACL
object = bucket.objects.find("lenna.png")
object.copy(:key => "lenna.png", :bucket => bucket, :acl => :private)
+=== Upload file direct to amazon
+
+==== Rails 3
+
+ To do that you just send file using proper form direct to amazon. You can create simple halper for that, for example like this one: https://gist.github.com/3169039
+
== See also
* rubygems[http://rubygems.org/gems/s3]
View
35 lib/s3/bucket.rb
@@ -4,14 +4,14 @@ class Bucket
include Proxies
extend Forwardable
- attr_reader :name, :service
+ attr_reader :name, :service, :acl
def_instance_delegators :service, :service_request
private_class_method :new
# Retrieves the bucket information from the server. Raises an
# S3::Error exception if the bucket doesn't exist or you don't
- # have access to it, etc.
+ # have access to it.
def retrieve
bucket_headers
self
@@ -30,6 +30,26 @@ def ==(other)
self.name == other.name and self.service == other.service
end
+ # Retrieves acl for bucket from the server.
+ #
+ # Return:
+ # hash: user|group => permission
+ def request_acl
+ body = bucket_request(:get, :params => "acl").body
+ parse_acl(body)
+ end
+
+ # Assigns a new ACL to the bucket. Please note that ACL is not
+ # retrieved from the server and set to "public-read" by default.
+ #
+ # Valid Values: :private | :public_read | :public_read_write | authenticated_read
+ #
+ # ==== Example
+ # bucket.acl = :public_read
+ def acl=(acl)
+ @acl = acl.to_s.gsub("_","-") if acl
+ end
+
# Similar to retrieve, but catches S3::Error::NoSuchBucket
# exceptions and returns false instead. Also catch S3::Error::ForbiddenBucket
# and return true
@@ -104,6 +124,14 @@ def inspect #:nodoc:
"#<#{self.class}:#{name}>"
end
+ def save_acl(options = {})
+ headers = {}
+ headers[:content_length] = 0
+ headers[:x_amz_acl] = options[:acl] || acl || "public-read"
+
+ response = bucket_request(:put, :headers => headers, :path => name)
+ end
+
private
attr_writer :service
@@ -141,7 +169,7 @@ def bucket_headers(options = {})
case e.response.code.to_i
when 404
raise Error::ResponseError.exception("NoSuchBucket").new("The specified bucket does not exist.", nil)
- when 403
+ when 403
raise Error::ResponseError.exception("ForbiddenBucket").new("The specified bucket exist but you do not have access to it.", nil)
else
raise e
@@ -180,5 +208,6 @@ def bucket_request(method, options = {})
def name_valid?(name)
name =~ /\A[a-z0-9][a-z0-9\._-]{2,254}\Z/i and name !~ /\A#{URI::REGEXP::PATTERN::IPV4ADDR}\Z/
end
+
end
end
View
2 lib/s3/connection.rb
@@ -128,7 +128,7 @@ def self.parse_params(params)
# Hash of headers translated from symbol to string, containing
# only interesting headers
def self.parse_headers(headers)
- interesting_keys = [:content_type, :cache_control, :x_amz_acl, :x_amz_storage_class, :range,
+ interesting_keys = [:content_type, :content_length, :cache_control, :x_amz_acl, :x_amz_storage_class, :range,
:if_modified_since, :if_unmodified_since,
:if_match, :if_none_match,
:content_disposition, :content_encoding,
View
17 lib/s3/object.rb
@@ -52,9 +52,11 @@ def storage_class=(storage_class)
end
# Retrieves the object from the server. Method is used to download
- # object information only (content type, size and so on). It does
- # NOT download the content of the object (use the #content method
- # to do it).
+ # object information only (content type, size).
+ # Notice: It does NOT download the content of the object
+ # (use the #content method to do it).
+ # Notice: this do not fetch acl information, use #request_acl
+ # method for that.
def retrieve
object_headers
self
@@ -70,6 +72,15 @@ def exists?
false
end
+ # Retrieves acl for object from the server.
+ #
+ # Return:
+ # hash: user|group => permission
+ def request_acl
+ response = object_request(:get, :params => "acl")
+ parse_acl(response.body)
+ end
+
# Downloads the content of the object, and caches it. Pass true to
# clear the cache and download the object again.
def content(reload = false)
View
38 lib/s3/parser.rb
@@ -48,5 +48,43 @@ def parse_error(xml)
def parse_is_truncated xml
rexml_document(xml).elements["ListBucketResult/IsTruncated"].text =='true'
end
+
+
+ # Parse acl response and return hash with grantee and their permissions
+ def parse_acl(xml)
+ grants = {}
+ rexml_document(xml).elements.each("AccessControlPolicy/AccessControlList/Grant") do |grant|
+ grants.merge!(extract_grantee(grant))
+ end
+ grants
+ end
+
+ private
+
+ def convert_uri_to_group_name(uri)
+ case uri
+ when "http://acs.amazonaws.com/groups/global/AllUsers"
+ return "Everyone"
+ when "http://acs.amazonaws.com/groups/global/AuthenticatedUsers"
+ return "Authenticated Users"
+ when "http://acs.amazonaws.com/groups/s3/LogDelivery"
+ return "Log Delivery"
+ else
+ return uri
+ end
+ end
+
+ def extract_grantee(grant)
+ grants = {}
+ grant.each_element_with_attribute("xsi:type", "Group") do |grantee|
+ group_name = convert_uri_to_group_name(grantee.get_text("URI").value)
+ grants[group_name] = grant.get_text("Permission").value
+ end
+ grant.each_element_with_attribute("xsi:type", "CanonicalUser") do |grantee|
+ user_name = grantee.get_text("DisplayName").value
+ grants[user_name] = grant.get_text("Permission").value
+ end
+ grants
+ end
end
end

0 comments on commit a1466c3

Please sign in to comment.