def id_from_userinfo(u): for a in u.get('Attributes', []): if not a.get('Name') == 'sub': continue return a['Value'] log.warn("Could not get an id for %s", u) return None
def user_phone_to_object(phonenumber, region=None): """ Converts a user provided phone number to a phone object :param phonenumber: :return: """ try: x = phonenumbers.parse(phonenumber) except phonenumbers.NumberParseException: log.warn("Failed to parse user provided number") else: return x if not region: log.debug("Could not parse %s", phonenumber) return None log.debug("Parsing %s w/ region", phonenumber) try: x = phonenumbers.parse(phonenumber, region=region) except phonenumbers.NumberParseException: log.warn("Failed to parse user provided number w/ region") else: return x return None
def send(event, context): idp_pool_id = get_mandatory_evar('COGNITO_IDP_POOL_ID') idp_pool_client_id = get_mandatory_evar('COGNITO_IDP_POOL_CLIENT_ID') log.debug("Event %s", event) if 'body' not in event: return {'statusCode': BAD_REQUEST, 'body': {'reason': "body"}} try: single_event = json.loads(event['body']) except TypeError: log.info("Failed loading body type=%s", type(event['body'])) if isinstance(event['body'], dict): single_event = event['body'] else: return { 'statusCode': BAD_REQUEST, 'body': { 'reason': 'Bad Body: \"%s\"' % event.get('body') } } original_phone_number = single_event.get('phonenumber') if not original_phone_number: return { 'statusCode': BAD_REQUEST, 'body': { 'reason': "missing phonenumber" } } phone_object = user_phone_to_object(original_phone_number) if not phone_object: # TODO: Base country code off the country code of calling country, agent-terminal-id, key, length? phone_object = user_phone_to_object(original_phone_number, region='MX') if not phone_object: return { 'statusCode': BAD_REQUEST, 'headers': headers, 'body': json.dumps({ "reason": "Bad phonenumber: \"%s\"" % (original_phone_number), }) } phone_number = phonenumbers.format_number( phone_object, phonenumbers.PhoneNumberFormat.E164) #TODO: test the phone number: # https://stackoverflow.com/a/23299989/1257603 # Also as an efficiency and performance measure: post to a queue and # do a bunch of messages at once auth_key = os.environ.get('PARAM_STORE_PRESHARED_KEY') log.debug("Retrieved Key: %s", auth_key) if not auth_key: return { 'statusCode': INTERNAL_SERVER_ERROR, 'body': { 'reason': 'must set preshared key' } } api_path = os.environ.get('api_path', 'ops-alpha/telco/outbound') posting_path = "https://api.athenabitcoin.net/%s" % api_path # Querying the user info before sending the code so that we can reduce the delay between sms code and user creation. user_info = get_userinfo_by_phone(phone_number) rand_code = random.randint(100000, 999999) for lang in ['language', 'lang']: if lang in single_event: break default_lang_code = 'en' #provided in swagger lang_code = single_event.get(lang) countrycode = phonenumbers.region_code_for_number(phone_object) if not lang_code: if countrycode in ('MX', 'CO', 'AR'): lang_code = 'es' else: lang_code = default_lang_code if lang_code == 'en': msg = 'Your code is: %s' % rand_code elif lang_code == 'es': msg = 'Voy a enviarte un código: %s' % rand_code else: log.warn("Bad Language code, %s, defaulting to %s", lang_code, default_lang_code) data = { 'phone_to': phone_number, 'message': msg, 'country': countrycode, 'method': 'sms' } log.debug("Posting to data: %s to %s. Time Remaining: %s", data, posting_path, context.get_remaining_time_in_millis()) try: z = requests.post(posting_path, headers={'Authorization': auth_key}, json=data, timeout=(context.get_remaining_time_in_millis() * .95 / 1000)) except TimeoutException, te: return { 'statusCode': GATEWAY_TIMEOUT, 'body': { 'reason': 'Unexpected delay in processing' } }
if response.get('ResponseMetadata', {}).get('HTTPStatusCode') not in (200, 201, 202): log.error("Failed to look up user successfully") return None users = response.get('Users') if not users: log.error("Failed retrieving users: %s", response) return None if len(users) == 0: log.error("No users found") return None if len(users) > 1: log.warn("More than one user in %s for %s (taking the first): %s", idp_pool_id, phoneno, users) return users[0] def authenticate_or_confirm_user(user_info): """ this method takes care of confiriming the users and nullifying the otp_info custom attribute :param user_info: :return: """ idp_pool_id = get_mandatory_evar('COGNITO_IDP_POOL_ID') log.debug("Checking the user confirmation status") if user_info['UserStatus'] == 'UNCONFIRMED': log.info("Confirming the user: {} ".format(user_info['Username'])) response = idp.admin_confirm_sign_up(UserPoolId=idp_pool_id,
sys.excepthook = original_except_hook try: tx.submit() finally: sys.excepthook = airbrake_except_hook tx_as_dict = tx.as_dict() try: tx_json = json.dumps(tx_as_dict, default=default_encode) except (TypeError, ValueError), e: log.exception("Failed to create tx as json") try: log.debug("Dictionary failed to convert: %s", tx_as_dict) except: log.warn("Could not even convert to dict") finally: return { 'statusCode': INTERNAL_SERVER_ERROR, 'body': { "message": "Object failed to serialize to json (%s)" % e }, 'headers': headers } else: return {'statusCode': OK, 'body': tx_json, 'headers': headers} def complete_transaction(event, context): """