def get_account_updates(account_request, existing_account): account_updates = {} delete_keys = set() if 'PlayerName' in account_request and existing_account.get( 'PlayerName') != account_request.get('PlayerName'): # IndexedPlayerName and PlayerNameSortKey are used to search accounts by name, case insensitive. See accountsearch.py account_updates['PlayerName'] = account_request['PlayerName'] account_updates['IndexedPlayerName'] = account_request[ 'PlayerName'].lower() account_updates['PlayerNameSortKey'] = randint( 1, account_utils.get_name_sort_key_count()) request_account_blacklisted = bool( account_request.get('AccountBlacklisted')) added_to_blacklist = False if 'AccountBlacklisted' in account_request and bool( existing_account.get( 'AccountBlacklisted')) != request_account_blacklisted: if request_account_blacklisted: account_updates['AccountBlacklisted'] = True added_to_blacklist = True else: delete_keys.add('AccountBlacklisted') if 'CognitoUsername' in account_request and existing_account.get( 'CognitoUsername') != account_request.get('CognitoUsername'): account_updates['CognitoUsername'] = account_request['CognitoUsername'] return account_updates, delete_keys, added_to_blacklist
def put(request, UpdateAccountRequest): if not request.event["cognitoIdentityId"]: raise errors.ForbiddenRequestError( 'The credentials used did not contain Cognito identity information' ) account_utils.validate_account_update_request(UpdateAccountRequest) account = account_utils.get_account_for_identity( request.event["cognitoIdentityId"]) if not account: account = { 'AccountId': str(uuid.uuid4()), 'CognitoIdentityId': request.event["cognitoIdentityId"] } if 'PlayerName' in UpdateAccountRequest: # IndexedPlayerName and PlayerNameSortKey are used to search accounts by name, case insensitive. See accountsearch.py account['PlayerName'] = UpdateAccountRequest['PlayerName'] account['IndexedPlayerName'] = UpdateAccountRequest[ 'PlayerName'].lower() account['PlayerNameSortKey'] = randint( 1, account_utils.get_name_sort_key_count()) account_utils.create_account(account) return account_utils.convert_account_from_dynamo_to_player_model( account) else: if account.get('AccountBlacklisted'): raise errors.ForbiddenRequestError('The account is blacklisted') updateRequest = {'AccountId': account['AccountId']} if 'PlayerName' in UpdateAccountRequest: # IndexedPlayerName and PlayerNameSortKey are used to search accounts by name, case insensitive. See accountsearch.py updateRequest['PlayerName'] = UpdateAccountRequest['PlayerName'] updateRequest['IndexedPlayerName'] = UpdateAccountRequest[ 'PlayerName'].lower() updateRequest['PlayerNameSortKey'] = randint( 1, account_utils.get_name_sort_key_count()) result = account_utils.update_account(updateRequest) return account_utils.convert_account_from_dynamo_to_player_model( result)
def search_by_start_name(StartPlayerName): sortKeyCount = account_utils.get_name_sort_key_count() limit = 20 accounts = [] # Accounts are randomly split across multiple partition keys in accounts.py to distribute load on the index. # This will collect results from all of the keys and combine them. for partition in range(1, sortKeyCount + 1): # The query limit is set to the same limit as the number of returned accounts in case the results all come from # the same partition key. An eventually consistent query consumes half a unit per 4KB regardless of how # many items contributed to the 4KB, so it's not too inefficient to read a lot of small items and throw most of them away. # This implementation expects searches to be relatively infrequent. queryArgs = { 'ConsistentRead': False, 'IndexName': 'PlayerNameIndex', 'KeyConditionExpression': Key('PlayerNameSortKey').eq(partition), 'Limit': limit, 'ScanIndexForward': True } if StartPlayerName: # Convert the inclusive start key from the request into an exclusive start key since Dynamo only supports exclusive. # Dynamo sorts keys by utf-8 bytes. This attempts to decrement the last byte so that it's one before # the start name. Not guaranteed to work in all cases. exclusiveStartKeyBytes = bytearray(StartPlayerName.lower(), 'utf-8') if exclusiveStartKeyBytes[-1] > 0: exclusiveStartKeyBytes[-1] = exclusiveStartKeyBytes[-1] - 1 exclusiveStartKey = exclusiveStartKeyBytes.decode( 'utf-8', 'ignore') queryArgs['ExclusiveStartKey'] = { 'PlayerNameSortKey': partition, 'IndexedPlayerName': exclusiveStartKey, 'AccountId': ' ' } response = account_utils.get_account_table().query(**queryArgs) for item in response.get('Items', []): accounts.append( account_utils.convert_account_from_dynamo_to_admin_model(item)) accounts.sort(cmp=account_utils.compare_accounts) if len(accounts) > limit: del accounts[limit:] populate_identity_providers(accounts) return {'Accounts': accounts}
def search_by_start_name(start_player_name=None, serialized_page_token=None): page_size = 20 config = dynamodb_pagination.PartitionedIndexConfig( table=account_utils.get_account_table(), index_name='PlayerNameIndex', partition_key_name='PlayerNameSortKey', sort_key_name='IndexedPlayerName', partition_count=account_utils.get_name_sort_key_count(), required_fields={'AccountId': ' '}) if serialized_page_token: page_token = dynamodb_pagination.PageToken(config, serialized_page_token) else: page_token = dynamodb_pagination.get_page_token_for_inclusive_start( config, start_player_name, forward=True) search = dynamodb_pagination.PaginatedSearch(config, page_token, start_player_name) raw_account_items = search.get_next_page(page_size) accounts = [ account_utils.convert_account_from_dynamo_to_admin_model(item) for item in raw_account_items ] populate_identity_providers(accounts) result = {'Accounts': accounts} forward_token = search.get_page_token(forward=True) if forward_token: result['next'] = forward_token backward_token = search.get_page_token(forward=False) if backward_token: result['previous'] = backward_token return result