mss-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +9 -0
  3. data/LICENSE.txt +0 -0
  4. data/README.md +192 -0
  5. data/bin/mss-rb +178 -0
  6. data/ca-bundle.crt +3554 -0
  7. data/lib/mss/core/async_handle.rb +89 -0
  8. data/lib/mss/core/cacheable.rb +76 -0
  9. data/lib/mss/core/client.rb +786 -0
  10. data/lib/mss/core/collection/simple.rb +81 -0
  11. data/lib/mss/core/collection/with_limit_and_next_token.rb +70 -0
  12. data/lib/mss/core/collection/with_next_token.rb +96 -0
  13. data/lib/mss/core/collection.rb +262 -0
  14. data/lib/mss/core/configuration.rb +527 -0
  15. data/lib/mss/core/credential_providers.rb +653 -0
  16. data/lib/mss/core/data.rb +251 -0
  17. data/lib/mss/core/deprecations.rb +83 -0
  18. data/lib/mss/core/endpoints.rb +36 -0
  19. data/lib/mss/core/http/connection_pool.rb +374 -0
  20. data/lib/mss/core/http/curb_handler.rb +150 -0
  21. data/lib/mss/core/http/handler.rb +88 -0
  22. data/lib/mss/core/http/net_http_handler.rb +144 -0
  23. data/lib/mss/core/http/patch.rb +98 -0
  24. data/lib/mss/core/http/request.rb +258 -0
  25. data/lib/mss/core/http/response.rb +80 -0
  26. data/lib/mss/core/indifferent_hash.rb +87 -0
  27. data/lib/mss/core/inflection.rb +55 -0
  28. data/lib/mss/core/ini_parser.rb +41 -0
  29. data/lib/mss/core/json_client.rb +46 -0
  30. data/lib/mss/core/json_parser.rb +75 -0
  31. data/lib/mss/core/json_request_builder.rb +34 -0
  32. data/lib/mss/core/json_response_parser.rb +78 -0
  33. data/lib/mss/core/lazy_error_classes.rb +107 -0
  34. data/lib/mss/core/log_formatter.rb +426 -0
  35. data/lib/mss/core/managed_file.rb +31 -0
  36. data/lib/mss/core/meta_utils.rb +44 -0
  37. data/lib/mss/core/model.rb +61 -0
  38. data/lib/mss/core/naming.rb +29 -0
  39. data/lib/mss/core/option_grammar.rb +737 -0
  40. data/lib/mss/core/options/json_serializer.rb +81 -0
  41. data/lib/mss/core/options/validator.rb +154 -0
  42. data/lib/mss/core/options/xml_serializer.rb +117 -0
  43. data/lib/mss/core/page_result.rb +74 -0
  44. data/lib/mss/core/policy.rb +938 -0
  45. data/lib/mss/core/query_client.rb +40 -0
  46. data/lib/mss/core/query_error_parser.rb +23 -0
  47. data/lib/mss/core/query_request_builder.rb +46 -0
  48. data/lib/mss/core/query_response_parser.rb +34 -0
  49. data/lib/mss/core/region.rb +84 -0
  50. data/lib/mss/core/region_collection.rb +79 -0
  51. data/lib/mss/core/resource.rb +412 -0
  52. data/lib/mss/core/resource_cache.rb +39 -0
  53. data/lib/mss/core/response.rb +214 -0
  54. data/lib/mss/core/response_cache.rb +49 -0
  55. data/lib/mss/core/rest_error_parser.rb +23 -0
  56. data/lib/mss/core/rest_json_client.rb +39 -0
  57. data/lib/mss/core/rest_request_builder.rb +153 -0
  58. data/lib/mss/core/rest_response_parser.rb +65 -0
  59. data/lib/mss/core/rest_xml_client.rb +46 -0
  60. data/lib/mss/core/service_interface.rb +82 -0
  61. data/lib/mss/core/signers/base.rb +45 -0
  62. data/lib/mss/core/signers/cloud_front.rb +55 -0
  63. data/lib/mss/core/signers/s3.rb +158 -0
  64. data/lib/mss/core/signers/version_2.rb +71 -0
  65. data/lib/mss/core/signers/version_3.rb +85 -0
  66. data/lib/mss/core/signers/version_3_https.rb +60 -0
  67. data/lib/mss/core/signers/version_4/chunk_signed_stream.rb +190 -0
  68. data/lib/mss/core/signers/version_4.rb +227 -0
  69. data/lib/mss/core/uri_escape.rb +43 -0
  70. data/lib/mss/core/xml/frame.rb +245 -0
  71. data/lib/mss/core/xml/frame_stack.rb +84 -0
  72. data/lib/mss/core/xml/grammar.rb +306 -0
  73. data/lib/mss/core/xml/parser.rb +69 -0
  74. data/lib/mss/core/xml/root_frame.rb +64 -0
  75. data/lib/mss/core/xml/sax_handlers/libxml.rb +46 -0
  76. data/lib/mss/core/xml/sax_handlers/nokogiri.rb +55 -0
  77. data/lib/mss/core/xml/sax_handlers/ox.rb +40 -0
  78. data/lib/mss/core/xml/sax_handlers/rexml.rb +46 -0
  79. data/lib/mss/core/xml/stub.rb +122 -0
  80. data/lib/mss/core.rb +602 -0
  81. data/lib/mss/errors.rb +161 -0
  82. data/lib/mss/rails.rb +194 -0
  83. data/lib/mss/s3/access_control_list.rb +262 -0
  84. data/lib/mss/s3/acl_object.rb +263 -0
  85. data/lib/mss/s3/acl_options.rb +200 -0
  86. data/lib/mss/s3/bucket.rb +757 -0
  87. data/lib/mss/s3/bucket_collection.rb +161 -0
  88. data/lib/mss/s3/bucket_lifecycle_configuration.rb +472 -0
  89. data/lib/mss/s3/bucket_region_cache.rb +51 -0
  90. data/lib/mss/s3/bucket_tag_collection.rb +110 -0
  91. data/lib/mss/s3/bucket_version_collection.rb +78 -0
  92. data/lib/mss/s3/cipher_io.rb +119 -0
  93. data/lib/mss/s3/client/xml.rb +265 -0
  94. data/lib/mss/s3/client.rb +2076 -0
  95. data/lib/mss/s3/config.rb +60 -0
  96. data/lib/mss/s3/cors_rule.rb +107 -0
  97. data/lib/mss/s3/cors_rule_collection.rb +193 -0
  98. data/lib/mss/s3/data_options.rb +190 -0
  99. data/lib/mss/s3/encryption_utils.rb +145 -0
  100. data/lib/mss/s3/errors.rb +93 -0
  101. data/lib/mss/s3/multipart_upload.rb +353 -0
  102. data/lib/mss/s3/multipart_upload_collection.rb +75 -0
  103. data/lib/mss/s3/object_collection.rb +355 -0
  104. data/lib/mss/s3/object_metadata.rb +102 -0
  105. data/lib/mss/s3/object_upload_collection.rb +76 -0
  106. data/lib/mss/s3/object_version.rb +153 -0
  107. data/lib/mss/s3/object_version_collection.rb +88 -0
  108. data/lib/mss/s3/paginated_collection.rb +74 -0
  109. data/lib/mss/s3/policy.rb +73 -0
  110. data/lib/mss/s3/prefix_and_delimiter_collection.rb +46 -0
  111. data/lib/mss/s3/prefixed_collection.rb +84 -0
  112. data/lib/mss/s3/presign_v4.rb +135 -0
  113. data/lib/mss/s3/presigned_post.rb +574 -0
  114. data/lib/mss/s3/region_detection.rb +75 -0
  115. data/lib/mss/s3/request.rb +61 -0
  116. data/lib/mss/s3/s3_object.rb +1795 -0
  117. data/lib/mss/s3/tree/branch_node.rb +67 -0
  118. data/lib/mss/s3/tree/child_collection.rb +103 -0
  119. data/lib/mss/s3/tree/leaf_node.rb +93 -0
  120. data/lib/mss/s3/tree/node.rb +21 -0
  121. data/lib/mss/s3/tree/parent.rb +86 -0
  122. data/lib/mss/s3/tree.rb +115 -0
  123. data/lib/mss/s3/uploaded_part.rb +81 -0
  124. data/lib/mss/s3/uploaded_part_collection.rb +83 -0
  125. data/lib/mss/s3/website_configuration.rb +101 -0
  126. data/lib/mss/s3.rb +161 -0
  127. data/lib/mss/version.rb +16 -0
  128. data/lib/mss-sdk.rb +2 -0
  129. data/lib/mss.rb +14 -0
  130. data/rails/init.rb +14 -0
  131. metadata +201 -0
data/lib/mss/errors.rb ADDED
@@ -0,0 +1,161 @@
1
+ # Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ #
8
+ # or in the "license" file accompanying this file. This file is
9
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
10
+ # ANY KIND, either express or implied. See the License for the specific
11
+ # language governing permissions and limitations under the License.
12
+
13
+ module MSS
14
+
15
+ # # Errors
16
+ #
17
+ # There are two basic types of errors:
18
+ #
19
+ # * {ClientError}
20
+ # * {ServerError}
21
+ #
22
+ # ## Client Errors
23
+ #
24
+ # Errors in the three and four hundreds are client errors ({ClientError}).
25
+ # A client error should not be resent without changes. The body of the
26
+ # http response (the error #message) should give more information about
27
+ # the nature of the problem.
28
+ #
29
+ # ## Server Errors
30
+ #
31
+ # A 500 level error typically indicates the service is having an issue.
32
+ #
33
+ # Requests that generate service errors are automatically retried with
34
+ # an exponential backoff. If the service still fails to respond with
35
+ # a 200 after 3 retries the error is raised.
36
+ #
37
+ module Errors
38
+
39
+ # Base class for all errors returned by the service.
40
+ class Base < StandardError
41
+
42
+ # @overload new(error_message)
43
+ # @param [String] error_message The body of the error message
44
+ #
45
+ # @overload new(http_request, http_response, code = nil, message = nil)
46
+ # @param [Http::Request] http_request
47
+ # @param [Http::Response] http_response
48
+ # @param [String] code (nil)
49
+ # @param [String] message (nil)
50
+ #
51
+ def initialize req = nil, resp = nil, code = nil, message = nil
52
+ if req.is_a?(String) or req.nil?
53
+ super(req)
54
+ else
55
+ @http_request = req
56
+ @http_response = resp
57
+ @code = code
58
+ include_error_type
59
+ super(message || http_response.body)
60
+ end
61
+ end
62
+
63
+ # @return [String] The response code given by the service.
64
+ attr_reader :code
65
+
66
+ # @return [Http::Request] The low level http request that caused the
67
+ # error to be raised.
68
+ attr_reader :http_request
69
+
70
+ # @return [Http::Response] The low level http response from the service
71
+ # that wrapped the service error.
72
+ attr_reader :http_response
73
+
74
+ protected
75
+
76
+ # Extends the error object with {ServerError} or {ClientError}.
77
+ # This indicates if the request should be retried (server errors)
78
+ # or not (client errors).
79
+ def include_error_type
80
+ if http_response.status >= 500
81
+ extend ServerError
82
+ else
83
+ extend ClientError
84
+ end
85
+ end
86
+
87
+ end
88
+
89
+ # Provides the ability to instantiate instances of {ServerError} and
90
+ # {ClientError}.
91
+ # @api private
92
+ module ExceptionMixinClassMethods
93
+ def new(*args)
94
+ e = Base.new(*args)
95
+ e.extend(self)
96
+ e
97
+ end
98
+ end
99
+
100
+ # Raised when an error occurs as a result of bad client
101
+ # behavior, most commonly when the parameters passed to a method
102
+ # are somehow invalid. Other common cases:
103
+ #
104
+ # * Throttling errors
105
+ # * Bad credentials
106
+ # * No permission to do the requested operation
107
+ # * Limits exceeded (e.g. too many buckets)
108
+ #
109
+ module ClientError
110
+ extend ExceptionMixinClassMethods
111
+ end
112
+
113
+ # Raised when an MSS service is unable to handle the request. These
114
+ # are automatically retired. If after 3 retries the request is still
115
+ # failing, then the error is raised.
116
+ module ServerError
117
+ extend ExceptionMixinClassMethods
118
+ end
119
+
120
+ # Raised when MSS credentials could not be found.
121
+ class MissingCredentialsError < StandardError
122
+
123
+ def initialize msg = nil
124
+ msg ||= <<-MSG
125
+
126
+ Missing Credentials.
127
+
128
+ Unable to find MSS credentials. You can configure your MSS credentials
129
+ a few different ways:
130
+
131
+ * Call MSS.config with :access_key_id and :secret_access_key
132
+
133
+ * Export MSS_ACCESS_KEY_ID and MSS_SECRET_ACCESS_KEY to ENV
134
+
135
+ * On EC2 you can run instances with an IAM instance profile and credentials
136
+ will be auto loaded from the instance metadata service on those
137
+ instances.
138
+
139
+ * Call MSS.config with :credential_provider. A credential provider should
140
+ either include MSS::Core::CredentialProviders::Provider or respond to
141
+ the same public methods.
142
+
143
+ = Ruby on Rails
144
+
145
+ In a Ruby on Rails application you may also specify your credentials in
146
+ the following ways:
147
+
148
+ * Via a config initializer script using any of the methods mentioned above
149
+ (e.g. RAILS_ROOT/config/initializers/mss-sdk.rb).
150
+
151
+ * Via a yaml configuration file located at RAILS_ROOT/config/mss.yml.
152
+ This file should be formated like the default RAILS_ROOT/config/database.yml
153
+ file.
154
+
155
+ MSG
156
+ super(msg)
157
+ end
158
+ end
159
+
160
+ end
161
+ end
data/lib/mss/rails.rb ADDED
@@ -0,0 +1,194 @@
1
+ # Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ #
8
+ # or in the "license" file accompanying this file. This file is
9
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
10
+ # ANY KIND, either express or implied. See the License for the specific
11
+ # language governing permissions and limitations under the License.
12
+
13
+ require 'yaml'
14
+
15
+ module MSS
16
+
17
+ if Object.const_defined?(:Rails) and Rails.const_defined?(:Railtie)
18
+
19
+ # @api private
20
+ class Railtie < Rails::Railtie
21
+
22
+ # configure our plugin on boot. other extension points such
23
+ # as configuration, rake tasks, etc, are also available
24
+ initializer "mss-sdk.initialize" do |app|
25
+ MSS::Rails.setup
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ # A handful of useful Rails integration methods.
32
+ #
33
+ # If you require this gem inside a Rails application (via config.gem
34
+ # for rails 2 and bundler for rails 3) then {setup} is called
35
+ # automatically.
36
+ module Rails
37
+
38
+ # Adds extra functionality to Rails.
39
+ #
40
+ # Normally this method is invoked automatically when you require this
41
+ # gem in a Rails Application:
42
+ #
43
+ # Rails 3+ (RAILS_ROOT/Gemfile)
44
+ #
45
+ # gem 'mss-sdk'
46
+ #
47
+ # Rails 2.1 - 2.3 (RAILS_ROOT/config/environment.rb)
48
+ #
49
+ # config.gem 'mss-sdk'
50
+ #
51
+ # @return [nil]
52
+ def self.setup
53
+ load_yaml_config
54
+ add_action_mailer_delivery_method
55
+ log_to_rails_logger
56
+ nil
57
+ end
58
+
59
+ # Loads MSS configuration options from `RAILS_ROOT/config/mss.yml`.
60
+ #
61
+ # This configuration file is optional. You can omit this file and instead
62
+ # use ruby to configure MSS inside a configuration initialization script
63
+ # (e.g. RAILS_ROOT/config/intializers/mss.rb).
64
+ #
65
+ # If you have a yaml configuration file it should be formatted like the
66
+ # standard `database.yml` file in a Rails application. This means there
67
+ # should be one section for Rails environment:
68
+ #
69
+ # development:
70
+ # access_key_id: YOUR_ACCESS_KEY_ID
71
+ # secret_access_key: YOUR_SECRET_ACCESS_KEY
72
+ # simple_db_consistent_reads: false
73
+ #
74
+ # production:
75
+ # access_key_id: YOUR_ACCESS_KEY_ID
76
+ # secret_access_key: YOUR_SECRET_ACCESS_KEY
77
+ # simple_db_consistent_reads: true
78
+ #
79
+ # You should also consider DRYing up your configuration file using
80
+ # YAML references:
81
+ #
82
+ # development:
83
+ # access_key_id: YOUR_ACCESS_KEY_ID
84
+ # secret_access_key: YOUR_SECRET_ACCESS_KEY
85
+ # simple_db_consistent_reads: false
86
+ #
87
+ # production:
88
+ # <<: *development
89
+ # simple_db_consistent_reads: true
90
+ #
91
+ # The yaml file will also be ERB parsed so you can use ruby inside of it:
92
+ #
93
+ # development:
94
+ # access_key_id: YOUR_ACCESS_KEY_ID
95
+ # secret_access_key: <%= read_secret_from_a_secure_location %>
96
+ # simple_db_consistent_reads: false
97
+ #
98
+ # production:
99
+ # <<: *development
100
+ # simple_db_consistent_reads: true
101
+ #
102
+ def self.load_yaml_config
103
+
104
+ path = Pathname.new("#{rails_root}/config/mss.yml")
105
+
106
+ if File.exist?(path)
107
+ cfg = YAML::load(ERB.new(File.read(path)).result)
108
+ unless cfg[rails_env]
109
+ raise "config/mss.yml is missing a section for `#{rails_env}`"
110
+ end
111
+ MSS.config(cfg[rails_env])
112
+ end
113
+
114
+ end
115
+
116
+ # Adds a delivery method to ActionMailer that uses
117
+ # {MSS::SimpleEmailService}.
118
+ #
119
+ # Once you have an SES delivery method you can configure Rails to
120
+ # use this for ActionMailer in your environment configuration
121
+ # (e.g. RAILS_ROOT/config/environments/production.rb)
122
+ #
123
+ # config.action_mailer.delivery_method = :amazon_ses
124
+ #
125
+ # ### Defaults
126
+ #
127
+ # Normally you don't need to call this method. By default a delivery method
128
+ # named `:amazon_ses` is added to ActionMailer::Base. This delivery method
129
+ # uses your default configuration (#{MSS.config}).
130
+ #
131
+ # ### Custom SES Options
132
+ #
133
+ # If you need to supply configuration values for SES that are different than
134
+ # those in {MSS.config} then you can pass those options:
135
+ #
136
+ # MSS::Rails.add_action_mailer_delivery_method(:ses, custom_options)
137
+ #
138
+ # @param [Symbol] name (:amazon_ses) The name of the delivery
139
+ # method. The name used here should be the same as you set in
140
+ # your environment config. If you name the delivery method
141
+ # `:amazon_ses` then you could do something like this in your
142
+ # config/environments/ENV.rb file:
143
+ #
144
+ # config.action_mailer.delivery_method = :amazon_ses
145
+ #
146
+ # @param [Hash] options A hash of options that are passes to
147
+ # {MSS::SimpleEmailService#new} before delivering email.
148
+ #
149
+ # @return [nil]
150
+ #
151
+ def self.add_action_mailer_delivery_method name = :amazon_ses, options = {}
152
+
153
+ if ::Rails.version.to_s >= '3.0'
154
+ ActiveSupport.on_load(:action_mailer) do
155
+ self.add_delivery_method(name, MSS::SimpleEmailService, options)
156
+ end
157
+ elsif defined?(::ActionMailer)
158
+ amb = ::ActionMailer::Base
159
+ amb.send(:define_method, "perform_delivery_#{name}") do |mail|
160
+ MSS::SimpleEmailService.new(options).send_raw_email(mail)
161
+ end
162
+ end
163
+
164
+ nil
165
+
166
+ end
167
+
168
+ # Configures MSS to log to the Rails default logger.
169
+ # @return [nil]
170
+ def self.log_to_rails_logger
171
+ MSS.config(:logger => rails_logger)
172
+ nil
173
+ end
174
+
175
+ # @api private
176
+ protected
177
+ def self.rails_env
178
+ ::Rails.respond_to?(:env) ? ::Rails.env : RAILS_ENV
179
+ end
180
+
181
+ # @api private
182
+ protected
183
+ def self.rails_root
184
+ ::Rails.respond_to?(:root) ? ::Rails.root.to_s : RAILS_ROOT
185
+ end
186
+
187
+ # @api private
188
+ protected
189
+ def self.rails_logger
190
+ ::Rails.respond_to?(:logger) ? ::Rails.logger : ::RAILS_DEFAULT_LOGGER
191
+ end
192
+
193
+ end
194
+ end
@@ -0,0 +1,262 @@
1
+ # Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ #
8
+ # or in the "license" file accompanying this file. This file is
9
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
10
+ # ANY KIND, either express or implied. See the License for the specific
11
+ # language governing permissions and limitations under the License.
12
+
13
+ module MSS
14
+ class S3
15
+
16
+ # Represents an access control list for S3 objects and buckets. For example:
17
+ #
18
+ # acl = AccessControlList.new
19
+ # acl.grant(:full_control).
20
+ # to(:canonical_user_id => "8a6925ce4adf588a4f21c32aa379004fef")
21
+ # acl.to_xml # => '<AccessControlPolicy>...'
22
+ #
23
+ # You can also construct an AccessControlList from a hash:
24
+ #
25
+ # AccessControlList.new(
26
+ # :owner => { :id => "8a6925ce4adf588a4f21c32aa379004fef" },
27
+ # :grants => [{
28
+ # :grantee => { :canonical_user_id => "8a6925ce4adf588a4f21c32aa379004fef" },
29
+ # :permission => :full_control,
30
+ # }]
31
+ # )
32
+ #
33
+ # @see ACLObject
34
+ #
35
+ # @attr [AccessControlList::Owner] owner The owner of the access
36
+ # control list. You can set this as a hash, for example:
37
+ # acl.owner = { :id => '8a6925ce4adf588a4f21c32aa379004fef' }
38
+ # This attribute is required when setting an ACL.
39
+ #
40
+ # @attr [list of AccessControlList::Grant] grants The list of
41
+ # grants. You can set this as a list of hashes, for example:
42
+ #
43
+ # acl.grants = [{
44
+ # :grantee => { :canonical_user_id => "8a6925ce4adf588a4f21c32aa379004fef" },
45
+ # :permission => :full_control,
46
+ # }]
47
+ class AccessControlList
48
+
49
+ # Represents an ACL owner. In the default ACL, this is the
50
+ # bucket owner.
51
+ #
52
+ # @attr [String] id The canonical user ID of the ACL owner.
53
+ # This attribute is required when setting an ACL.
54
+ #
55
+ # @attr [String] display_name The display name of the ACL
56
+ # owner. This value is ignored when setting an ACL.
57
+ class Owner
58
+ include ACLObject
59
+
60
+ string_attr "ID", :required => true
61
+ string_attr "DisplayName"
62
+ end
63
+
64
+ # Represents a user who is granted some kind of permission
65
+ # through a Grant. There are three ways to specify a grantee:
66
+ #
67
+ # * You can specify the canonical user ID, for example. When
68
+ # you read an ACL from S3, all grantees will be identified
69
+ # this way, and the display_name attribute will also be provided.
70
+ #
71
+ # Grantee.new(:canonical_user_id => "8a6925ce4adf588a4f21c32aa379004fef")
72
+ #
73
+ # * You can specify the e-mail address of an MSS customer, for example:
74
+ #
75
+ # Grantee.new(:amazon_customer_email => 'foo@example.com')
76
+ #
77
+ # * You can specify a group URI, for example:
78
+ #
79
+ # Grantee.new(:group_uri => 'http://acs.amazonmss.com/groups/global/AllUsers')
80
+ #
81
+ # For more details about group URIs, see:
82
+ #
83
+ # When constructing a grantee, you must provide a value for
84
+ # exactly one of the following attributes:
85
+ #
86
+ # * `amazon_customer_email`
87
+ # * `canonical_user_id`
88
+ # * `group_uri`
89
+ #
90
+ # @attr [String] amazon_customer_email The e-mail address of
91
+ # an MSS customer.
92
+ #
93
+ # @attr [String] canonical_user_id The canonical user ID of an
94
+ # MSS customer.
95
+ #
96
+ # @attr [String] group_uri A URI that identifies a particular
97
+ # group of users.
98
+ #
99
+ # @attr [String] display_name The display name associated with
100
+ # the grantee. This is provided by S3 when reading an ACL.
101
+ class Grantee
102
+ include ACLObject
103
+
104
+ SIGNAL_ATTRIBUTES = [
105
+ :amazon_customer_email,
106
+ :canonical_user_id,
107
+ :group_uri,
108
+ :uri,
109
+ ]
110
+
111
+ string_attr "EmailAddress", :method_name => "amazon_customer_email"
112
+ string_attr "ID", :method_name => "canonical_user_id"
113
+ string_attr "URI", :method_name => "group_uri"
114
+ string_attr "URI", :method_name => "uri"
115
+ string_attr "DisplayName"
116
+
117
+ # (see ACLObject#validate!)
118
+ def validate!
119
+ attr = signal_attribute
120
+ raise "missing amazon_customer_email, canonical_user_id, "+
121
+ "or group_uri" unless attr
122
+ raise "display_name is invalid with #{attr}" if
123
+ attr != :canonical_user_id and display_name
124
+ end
125
+
126
+ # @api private
127
+ def stag
128
+ if attr = signal_attribute
129
+ super + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
130
+ " xsi:type=\"#{type_for_attr(attr)}\""
131
+ else
132
+ super
133
+ end
134
+ end
135
+
136
+ # @api private
137
+ def signal_attribute
138
+ SIGNAL_ATTRIBUTES.find { |att| send(att) }
139
+ end
140
+
141
+ # @api private
142
+ def type_for_attr(attr)
143
+ {
144
+ :amazon_customer_email => "AmazonCustomerByEmail",
145
+ :canonical_user_id => "CanonicalUser",
146
+ :group_uri => "Group",
147
+ :uri => "Group",
148
+ }[attr]
149
+ end
150
+
151
+ end
152
+
153
+ # Represents the permission being granted in a Grant object.
154
+ # Typically you will not need to construct an instance of this
155
+ # class directly.
156
+ # @see Grant#permission
157
+ class Permission
158
+ include ACLObject
159
+
160
+ # The permission expressed as a symbol following Ruby
161
+ # conventions. For example, S3's FULL_CONTROL permission
162
+ # will be returned as `:full_control`.
163
+ attr_reader :name
164
+
165
+ # @api private
166
+ def initialize(name)
167
+ raise "expected string or symbol" unless
168
+ name.respond_to?(:to_str) or name.respond_to?(:to_sym)
169
+ @name = name.to_sym
170
+ end
171
+
172
+ def body_xml
173
+ name.to_s.upcase
174
+ end
175
+
176
+ end
177
+
178
+ # Represents a single grant in an ACL. Both `grantee` and
179
+ # `permission` are required for each grant when setting an
180
+ # ACL.
181
+ #
182
+ # See
183
+ # for more information on how grantees and permissions are
184
+ # interpreted by S3.
185
+ #
186
+ # @attr [Grantee] grantee The user or users who are granted
187
+ # access according to this grant. You can specify this as a
188
+ # hash:
189
+ #
190
+ # grant.grantee = { :amazon_customer_email => "foo@example.com" }
191
+ #
192
+ # @attr [Permission or Symbol] permission The type of
193
+ # permission that is granted by this grant. Valid values are:
194
+ # * `:read`
195
+ # * `:write`
196
+ # * `:read_acp`
197
+ # * `:write_acp`
198
+ # * `:full_control`
199
+ class Grant
200
+
201
+ include ACLObject
202
+
203
+ object_attr Grantee, :required => true
204
+ object_attr Permission, :required => true, :cast => Symbol
205
+
206
+ end
207
+
208
+ include ACLObject
209
+
210
+ # @api private
211
+ def stag
212
+ super()+" xmlns=\"http://s3.amazonmss.com/doc/2006-03-01/\""
213
+ end
214
+
215
+ # @api private
216
+ def element_name
217
+ "AccessControlPolicy"
218
+ end
219
+
220
+ class GrantBuilder
221
+
222
+ # @api private
223
+ def initialize(acl, grant)
224
+ @acl = acl
225
+ @grant = grant
226
+ end
227
+
228
+ # Specifies the grantee.
229
+ #
230
+ # @param [Grantee or Hash] grantee A Grantee object or hash;
231
+ # for example:
232
+ #
233
+ # acl.grant(:full_control).to(:amazon_customer_email => "foo@example.com")
234
+ def to(grantee)
235
+ @grant.grantee = grantee
236
+ @acl.grants << @grant
237
+ end
238
+
239
+ end
240
+
241
+ # Convenience method for constructing a new grant and adding
242
+ # it to the ACL.
243
+ #
244
+ # @example
245
+ #
246
+ # acl.grants.size # => 0
247
+ # acl.grant(:full_control).to(:canonical_user_id => "8a6925ce4adf588a4f21c32aa379004fef")
248
+ # acl.grants.size # => 1
249
+ #
250
+ # @return [GrantBuilder]
251
+ def grant(permission)
252
+ GrantBuilder.new(self, Grant.new(:permission => permission))
253
+ end
254
+
255
+ object_attr Owner, :required => true
256
+ object_list_attr("AccessControlList", Grant,
257
+ :required => true, :method_name => :grants)
258
+
259
+ end
260
+
261
+ end
262
+ end