Index: third_party/gsutil/boto/boto/fps/connection.py |
diff --git a/third_party/gsutil/boto/boto/fps/connection.py b/third_party/gsutil/boto/boto/fps/connection.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3b9057e4bba59839d7ed57660a0a35430d8f8879 |
--- /dev/null |
+++ b/third_party/gsutil/boto/boto/fps/connection.py |
@@ -0,0 +1,369 @@ |
+# Copyright (c) 2012 Andy Davidoff http://www.disruptek.com/ |
+# Copyright (c) 2010 Jason R. Coombs http://www.jaraco.com/ |
+# Copyright (c) 2008 Chris Moyer http://coredumped.org/ |
+# |
+# Permission is hereby granted, free of charge, to any person obtaining a |
+# copy of this software and associated documentation files (the |
+# "Software"), to deal in the Software without restriction, including |
+# without limitation the rights to use, copy, modify, merge, publish, dis- |
+# tribute, sublicense, and/or sell copies of the Software, and to permit |
+# persons to whom the Software is furnished to do so, subject to the fol- |
+# lowing conditions: |
+# |
+# The above copyright notice and this permission notice shall be included |
+# in all copies or substantial portions of the Software. |
+# |
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- |
+# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT |
+# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
+# IN THE SOFTWARE. |
+ |
+import urllib |
+import uuid |
+from boto.connection import AWSQueryConnection |
+from boto.fps.exception import ResponseErrorFactory |
+from boto.fps.response import ResponseFactory |
+import boto.fps.response |
+ |
+__all__ = ['FPSConnection'] |
+ |
+decorated_attrs = ('action', 'response') |
+ |
+ |
+def add_attrs_from(func, to): |
+ for attr in decorated_attrs: |
+ setattr(to, attr, getattr(func, attr, None)) |
+ return to |
+ |
+ |
+def complex_amounts(*fields): |
+ def decorator(func): |
+ def wrapper(self, *args, **kw): |
+ for field in filter(kw.has_key, fields): |
+ amount = kw.pop(field) |
+ kw[field + '.Value'] = getattr(amount, 'Value', str(amount)) |
+ kw[field + '.CurrencyCode'] = getattr(amount, 'CurrencyCode', |
+ self.currencycode) |
+ return func(self, *args, **kw) |
+ wrapper.__doc__ = "{0}\nComplex Amounts: {1}".format(func.__doc__, |
+ ', '.join(fields)) |
+ return add_attrs_from(func, to=wrapper) |
+ return decorator |
+ |
+ |
+def requires(*groups): |
+ |
+ def decorator(func): |
+ |
+ def wrapper(*args, **kw): |
+ hasgroup = lambda x: len(x) == len(filter(kw.has_key, x)) |
+ if 1 != len(filter(hasgroup, groups)): |
+ message = ' OR '.join(['+'.join(g) for g in groups]) |
+ message = "{0} requires {1} argument(s)" \ |
+ "".format(getattr(func, 'action', 'Method'), message) |
+ raise KeyError(message) |
+ return func(*args, **kw) |
+ message = ' OR '.join(['+'.join(g) for g in groups]) |
+ wrapper.__doc__ = "{0}\nRequired: {1}".format(func.__doc__, |
+ message) |
+ return add_attrs_from(func, to=wrapper) |
+ return decorator |
+ |
+ |
+def needs_caller_reference(func): |
+ |
+ def wrapper(*args, **kw): |
+ kw.setdefault('CallerReference', uuid.uuid4()) |
+ return func(*args, **kw) |
+ wrapper.__doc__ = "{0}\nUses CallerReference, defaults " \ |
+ "to uuid.uuid4()".format(func.__doc__) |
+ return add_attrs_from(func, to=wrapper) |
+ |
+ |
+def api_action(*api): |
+ |
+ def decorator(func): |
+ action = ''.join(api or map(str.capitalize, func.func_name.split('_'))) |
+ response = ResponseFactory(action) |
+ if hasattr(boto.fps.response, action + 'Response'): |
+ response = getattr(boto.fps.response, action + 'Response') |
+ |
+ def wrapper(self, *args, **kw): |
+ return func(self, action, response, *args, **kw) |
+ wrapper.action, wrapper.response = action, response |
+ wrapper.__doc__ = "FPS {0} API call\n{1}".format(action, |
+ func.__doc__) |
+ return wrapper |
+ return decorator |
+ |
+ |
+class FPSConnection(AWSQueryConnection): |
+ |
+ APIVersion = '2010-08-28' |
+ ResponseError = ResponseErrorFactory |
+ currencycode = 'USD' |
+ |
+ def __init__(self, *args, **kw): |
+ self.currencycode = kw.pop('CurrencyCode', self.currencycode) |
+ kw.setdefault('host', 'fps.sandbox.amazonaws.com') |
+ AWSQueryConnection.__init__(self, *args, **kw) |
+ |
+ def _required_auth_capability(self): |
+ return ['fps'] |
+ |
+ @needs_caller_reference |
+ @complex_amounts('SettlementAmount') |
+ @requires(['CreditInstrumentId', 'SettlementAmount.Value', |
+ 'SenderTokenId', 'SettlementAmount.CurrencyCode']) |
+ @api_action() |
+ def settle_debt(self, action, response, **kw): |
+ """Allows a caller to initiate a transaction that atomically |
+ transfers money from a sender's payment instrument to the |
+ recipient, while decreasing corresponding debt balance. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @requires(['TransactionId']) |
+ @api_action() |
+ def get_transaction_status(self, action, response, **kw): |
+ """Gets the latest status of a transaction. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @requires(['StartDate']) |
+ @api_action() |
+ def get_account_activity(self, action, response, **kw): |
+ """Returns transactions for a given date range. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @requires(['TransactionId']) |
+ @api_action() |
+ def get_transaction(self, action, response, **kw): |
+ """Returns all details of a transaction. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @api_action() |
+ def get_outstanding_debt_balance(self, action, response): |
+ """Returns the total outstanding balance for all the credit |
+ instruments for the given creditor account. |
+ """ |
+ return self.get_object(action, {}, response) |
+ |
+ @requires(['PrepaidInstrumentId']) |
+ @api_action() |
+ def get_prepaid_balance(self, action, response, **kw): |
+ """Returns the balance available on the given prepaid instrument. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @api_action() |
+ def get_total_prepaid_liability(self, action, response): |
+ """Returns the total liability held by the given account |
+ corresponding to all the prepaid instruments owned by the |
+ account. |
+ """ |
+ return self.get_object(action, {}, response) |
+ |
+ @api_action() |
+ def get_account_balance(self, action, response): |
+ """Returns the account balance for an account in real time. |
+ """ |
+ return self.get_object(action, {}, response) |
+ |
+ @needs_caller_reference |
+ @requires(['PaymentInstruction', 'TokenType']) |
+ @api_action() |
+ def install_payment_instruction(self, action, response, **kw): |
+ """Installs a payment instruction for caller. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @needs_caller_reference |
+ @requires(['returnURL', 'pipelineName']) |
+ def cbui_url(self, **kw): |
+ """Generate a signed URL for the Co-Branded service API given |
+ arguments as payload. |
+ """ |
+ sandbox = 'sandbox' in self.host and 'payments-sandbox' or 'payments' |
+ endpoint = 'authorize.{0}.amazon.com'.format(sandbox) |
+ base = '/cobranded-ui/actions/start' |
+ |
+ validpipelines = ('SingleUse', 'MultiUse', 'Recurring', 'Recipient', |
+ 'SetupPrepaid', 'SetupPostpaid', 'EditToken') |
+ assert kw['pipelineName'] in validpipelines, "Invalid pipelineName" |
+ kw.update({ |
+ 'signatureMethod': 'HmacSHA256', |
+ 'signatureVersion': '2', |
+ }) |
+ kw.setdefault('callerKey', self.aws_access_key_id) |
+ |
+ safestr = lambda x: x is not None and str(x) or '' |
+ safequote = lambda x: urllib.quote(safestr(x), safe='~') |
+ payload = sorted([(k, safequote(v)) for k, v in kw.items()]) |
+ |
+ encoded = lambda p: '&'.join([k + '=' + v for k, v in p]) |
+ canonical = '\n'.join(['GET', endpoint, base, encoded(payload)]) |
+ signature = self._auth_handler.sign_string(canonical) |
+ payload += [('signature', safequote(signature))] |
+ payload.sort() |
+ |
+ return 'https://{0}{1}?{2}'.format(endpoint, base, encoded(payload)) |
+ |
+ @needs_caller_reference |
+ @complex_amounts('TransactionAmount') |
+ @requires(['SenderTokenId', 'TransactionAmount.Value', |
+ 'TransactionAmount.CurrencyCode']) |
+ @api_action() |
+ def reserve(self, action, response, **kw): |
+ """Reserve API is part of the Reserve and Settle API conjunction |
+ that serve the purpose of a pay where the authorization and |
+ settlement have a timing difference. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @needs_caller_reference |
+ @complex_amounts('TransactionAmount') |
+ @requires(['SenderTokenId', 'TransactionAmount.Value', |
+ 'TransactionAmount.CurrencyCode']) |
+ @api_action() |
+ def pay(self, action, response, **kw): |
+ """Allows calling applications to move money from a sender to |
+ a recipient. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @requires(['TransactionId']) |
+ @api_action() |
+ def cancel(self, action, response, **kw): |
+ """Cancels an ongoing transaction and puts it in cancelled state. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @complex_amounts('TransactionAmount') |
+ @requires(['ReserveTransactionId', 'TransactionAmount.Value', |
+ 'TransactionAmount.CurrencyCode']) |
+ @api_action() |
+ def settle(self, action, response, **kw): |
+ """The Settle API is used in conjunction with the Reserve API and |
+ is used to settle previously reserved transaction. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @complex_amounts('RefundAmount') |
+ @requires(['TransactionId', 'RefundAmount.Value', |
+ 'CallerReference', 'RefundAmount.CurrencyCode']) |
+ @api_action() |
+ def refund(self, action, response, **kw): |
+ """Refunds a previously completed transaction. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @requires(['RecipientTokenId']) |
+ @api_action() |
+ def get_recipient_verification_status(self, action, response, **kw): |
+ """Returns the recipient status. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @requires(['CallerReference'], ['TokenId']) |
+ @api_action() |
+ def get_token_by_caller(self, action, response, **kw): |
+ """Returns the details of a particular token installed by this |
+ calling application using the subway co-branded UI. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @requires(['UrlEndPoint', 'HttpParameters']) |
+ @api_action() |
+ def verify_signature(self, action, response, **kw): |
+ """Verify the signature that FPS sent in IPN or callback urls. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @api_action() |
+ def get_tokens(self, action, response, **kw): |
+ """Returns a list of tokens installed on the given account. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @requires(['TokenId']) |
+ @api_action() |
+ def get_token_usage(self, action, response, **kw): |
+ """Returns the usage of a token. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @requires(['TokenId']) |
+ @api_action() |
+ def cancel_token(self, action, response, **kw): |
+ """Cancels any token installed by the calling application on |
+ its own account. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @needs_caller_reference |
+ @complex_amounts('FundingAmount') |
+ @requires(['PrepaidInstrumentId', 'FundingAmount.Value', |
+ 'SenderTokenId', 'FundingAmount.CurrencyCode']) |
+ @api_action() |
+ def fund_prepaid(self, action, response, **kw): |
+ """Funds the prepaid balance on the given prepaid instrument. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @requires(['CreditInstrumentId']) |
+ @api_action() |
+ def get_debt_balance(self, action, response, **kw): |
+ """Returns the balance corresponding to the given credit instrument. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @needs_caller_reference |
+ @complex_amounts('AdjustmentAmount') |
+ @requires(['CreditInstrumentId', 'AdjustmentAmount.Value', |
+ 'AdjustmentAmount.CurrencyCode']) |
+ @api_action() |
+ def write_off_debt(self, action, response, **kw): |
+ """Allows a creditor to write off the debt balance accumulated |
+ partially or fully at any time. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @requires(['SubscriptionId']) |
+ @api_action() |
+ def get_transactions_for_subscription(self, action, response, **kw): |
+ """Returns the transactions for a given subscriptionID. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @requires(['SubscriptionId']) |
+ @api_action() |
+ def get_subscription_details(self, action, response, **kw): |
+ """Returns the details of Subscription for a given subscriptionID. |
+ """ |
+ return self.get_object(action, kw, response) |
+ |
+ @needs_caller_reference |
+ @complex_amounts('RefundAmount') |
+ @requires(['SubscriptionId']) |
+ @api_action() |
+ def cancel_subscription_and_refund(self, action, response, **kw): |
+ """Cancels a subscription. |
+ """ |
+ message = "If you specify a RefundAmount, " \ |
+ "you must specify CallerReference." |
+ assert not 'RefundAmount.Value' in kw \ |
+ or 'CallerReference' in kw, message |
+ return self.get_object(action, kw, response) |
+ |
+ @requires(['TokenId']) |
+ @api_action() |
+ def get_payment_instruction(self, action, response, **kw): |
+ """Gets the payment instruction of a token. |
+ """ |
+ return self.get_object(action, kw, response) |