def create_provider_ownership(table, handle, new_owner_name, raid_name): """ Create ownership index for a new provider or convert existing one :param table: :param handle: :param new_owner_name: :param raid_name: :return: """ # Get current datetime association_datetime = raid_helpers.get_current_datetime() # Check if new owner exists and end normal association existing_provider_query_parameters = { 'IndexName': 'HandleNameIndex', 'ProjectionExpression': "startDate, endDate", 'FilterExpression': Attr('endDate').not_exists(), 'KeyConditionExpression': Key('handle-name').eq('{}-{}'.format(handle, new_owner_name)) } existing_provider_query_response = table.query( **existing_provider_query_parameters) existing_providers = existing_provider_query_response["Items"] if existing_provider_query_response["Count"] > 0: association_datetime = existing_providers[0]['startDate'] # Remove indexed previous owner table.delete_item(Key={ 'startDate': existing_providers[0]['startDate'], 'handle': handle }, ReturnValues='ALL_OLD') # Create new association new_owner_item = { 'handle': handle, 'startDate': association_datetime, 'name': new_owner_name, 'raidName': raid_name, 'type': settings.SERVICE_ROLE, 'handle-name': '{}-{}'.format(handle, new_owner_name), 'handle-type': '{}-{}'.format(handle, settings.SERVICE_ROLE), 'role': 'owner', 'name-role': '{}-{}'.format(new_owner_name, 'owner'), } table.put_item(Item=new_owner_item)
def create_raid_handler(event, context): """ Create and new RAiD by; generating a handle, registering with ANDS and putting to the RAiD DB and Provider Index. :param event: :param context: :return: RAiD object """ if 'requestContext' not in event: return {"message": "Warming Lambda container"} try: environment = event['requestContext']['authorizer']['environment'] owner = event['requestContext']['authorizer']['provider'] # Initialise DynamoDB dynamo_db = boto3.resource('dynamodb') raid_table = dynamo_db.Table( settings.get_environment_table(settings.RAID_TABLE, environment)) # Get current datetime now = raid_helpers.get_current_datetime() # Define Initial RAiD item raid_item = {'creationDate': now, 'owner': owner} # Interpret and validate request body if 'body' in event and event["body"]: body = json.loads(event["body"]) # Check for provided content path to mint if "contentPath" in body: content_path = body["contentPath"] else: content_path = settings.RAID_SITE_URL if "meta" in body: raid_item['meta'] = body['meta'] else: raid_item['meta'] = {} # Auto-generate RAiD descriptive fields if they do not exist if 'name' not in raid_item['meta']: raid_item['meta'] = { 'name': raid_helpers.generate_random_name() } if 'description' not in raid_item['meta']: raid_item['meta'][ 'description'] = "RAiD created by '{}' at '{}'".format( owner, now) if "startDate" in body: try: start_date = body["startDate"] datetime.datetime.strptime(start_date, "%Y-%m-%d %H:%M:%S") raid_item['startDate'] = start_date except ValueError as e: logger.error('Unable to capture date: {}'.format(e)) return web_helpers.generate_web_body_response( '400', { 'message': "Incorrect date format, should be yyyy-MM-dd hh:mm:ss" }, event) else: raid_item['startDate'] = now else: content_path = settings.RAID_SITE_URL raid_item['startDate'] = now # Set content path raid_item['contentPath'] = content_path # Get correct ANDS Shared Secret if environment == settings.DEMO_ENVIRONMENT: ands_secret = os.environ["ANDS_DEMO_SECRET"] elif environment == settings.LIVE_ENVIRONMENT: ands_secret = os.environ["ANDS_SECRET"] # Get ANDS handle and content index ands_handle, ands_content_index = ands_helpers.get_new_ands_handle( environment, os.environ["ANDS_HANDLES_QUEUE"], os.environ["DEMO_ANDS_HANDLES_QUEUE"], os.environ["ANDS_SERVICE"], os.environ["DEMO_ANDS_SERVICE"], content_path, os.environ["ANDS_APP_ID"], ands_secret) # Insert minted handle into raid item raid_item['handle'] = ands_handle raid_item['contentIndex'] = ands_content_index # Send Dynamo DB put for new RAiD raid_table.put_item(Item=raid_item) # Define provider association item # TODO move to DynamoDB Stream service_item = { 'handle': ands_handle, 'startDate': raid_item['startDate'], 'name': owner, 'raidName': raid_item['meta']['name'], 'role': 'owner', 'type': settings.SERVICE_ROLE, 'name-role': '{}-{}'.format(owner, 'owner'), 'handle-name': '{}-{}'.format(ands_handle, owner), 'handle-type': '{}-{}'.format(ands_handle, settings.SERVICE_ROLE) } # Send Dynamo DB put for new association association_index_table = dynamo_db.Table( settings.get_environment_table(settings.ASSOCIATION_TABLE, environment)) association_index_table.put_item( Item=service_item) # TODO move to DynamoDB Stream raid_item['providers'] = [{ 'provider': service_item['name'], 'startDate': service_item['startDate'] }] return web_helpers.generate_web_body_response('200', raid_item, event) except ands_helpers.AndsMintingError as e: logger.error( 'Unable to mint content path for RAiD creation: {}'.format(e)) return web_helpers.generate_web_body_response( '500', { 'message': "Unable to create a RAiD as ANDS was unable to mint the content path." }, event) except Exception as e: logger.error('Unable to create RAiD: {}'.format(e)) return web_helpers.generate_web_body_response( '400', { 'message': "Unable to perform request due to error. Please check structure of the body." }, event)
def create_raid_provider_association_handler(event, context): """ Create a new provider association to a RAiD :param event: :param context: :return: """ try: raid_handle = urllib.unquote(urllib.unquote(event["pathParameters"]["raidId"])) except: logger.error('Unable to validate RAiD parameter: {}'.format(sys.exc_info()[0])) return web_helpers.generate_web_body_response( '400', {'message': "Incorrect path parameter type formatting for RAiD handle. Ensure it is a URL encoded string"}, event ) try: environment = event['requestContext']['authorizer']['environment'] # Initialise DynamoDB dynamo_db = boto3.resource('dynamodb') raid_table = dynamo_db.Table( settings.get_environment_table(settings.RAID_TABLE, environment) ) # Check if RAiD exists query_response = raid_table.query(KeyConditionExpression=Key('handle').eq(raid_handle)) if query_response["Count"] != 1: return web_helpers.generate_web_body_response('400', { 'message': "Invalid RAiD handle provided in parameter path. " "Ensure it is a valid RAiD handle URL encoded string"}, event) # Assign raid item to single item, since the result will be an array of one item raid_item = query_response['Items'][0] # Interpret and validate request body body = json.loads(event["body"]) if "startDate" in body: try: start_date = datetime.datetime.strptime(body["startDate"], "%Y-%m-%d %H:%M:%S") except ValueError as e: logger.error('Unable to capture date: {}'.format(e)) return web_helpers.generate_web_body_response('400', { 'message': "Incorrect date format, should be yyyy-MM-dd hh:mm:ss"}, event) else: # Get current datetime start_date = raid_helpers.get_current_datetime() if "name" not in body: return web_helpers.generate_web_body_response('400', { 'message': "'name' must be provided in your request body to create an association"}, event) # Define provider association item service_item = { 'handle': raid_handle, 'startDate': start_date, 'name': body['name'], 'raidName': raid_item['meta']['name'], 'type': settings.SERVICE_ROLE, 'handle-name': '{}-{}'.format(raid_handle, body['name']), 'handle-type': '{}-{}'.format(raid_handle, settings.SERVICE_ROLE) } # Send Dynamo DB put for new association association_index_table = dynamo_db.Table( settings.get_environment_table( settings.ASSOCIATION_TABLE, environment ) ) association_index_table.put_item(Item=service_item) return web_helpers.generate_web_body_response('200', { 'name': service_item['name'], 'startDate': service_item['startDate'] }, event) except: logger.error('Unable to associate a provider to a RAiD: {}'.format(sys.exc_info()[0])) return web_helpers.generate_web_body_response('500', { 'message': "Unable to perform request due to error. Please check structure of the body."}, event)
def end_raid_provider_association_handler(event, context): """ End a provider association to a RAiD :param event: :param context: :return: """ try: raid_handle = urllib.unquote(urllib.unquote(event["pathParameters"]["raidId"])) except: logger.error('Unable to validate RAiD parameter: {}'.format(sys.exc_info()[0])) return web_helpers.generate_web_body_response( '400', {'message': "Incorrect path parameter type formatting for RAiD handle. Ensure it is a URL encoded string"}, event ) try: environment = event['requestContext']['authorizer']['environment'] # Initialise DynamoDB dynamo_db = boto3.resource('dynamodb') raid_table = dynamo_db.Table(settings.get_environment_table(settings.RAID_TABLE, environment)) # Check if RAiD exists query_response = raid_table.query(KeyConditionExpression=Key('handle').eq(raid_handle)) if query_response["Count"] != 1: return web_helpers.generate_web_body_response('400', { 'message': "Invalid RAiD handle provided in parameter path. " "Ensure it is a valid RAiD handle URL encoded string"}, event) # Interpret and validate request body body = json.loads(event["body"]) if "endDate" in body: try: end_date = datetime.datetime.strptime(body["endDate"], "%Y-%m-%d %H:%M:%S") except ValueError as e: logger.error('Unable to capture date: {}'.format(e)) return web_helpers.generate_web_body_response('400', { 'message': "Incorrect date format, should be yyyy-MM-dd hh:mm:ss"}, event) else: # Get current datetime end_date = raid_helpers.get_current_datetime() if "name" not in body: return web_helpers.generate_web_body_response('400', { 'message': "'name' must be provided in your request body to end an association"}, event) # Update DynamoDB put to end association association_index_table = dynamo_db.Table( settings.get_environment_table( settings.ASSOCIATION_TABLE, environment ) ) existing_provider_query_parameters = { 'IndexName': 'HandleNameIndex', 'ProjectionExpression': "startDate, endDate", 'FilterExpression': Attr('endDate').not_exists(), 'KeyConditionExpression': Key('handle-name').eq('{}-{}'.format(raid_handle, body['name'])) } provider_query_response = association_index_table.query(**existing_provider_query_parameters) existing_provider = provider_query_response["Items"][0] # Get existing item update_response = association_index_table.update_item( Key={ 'startDate': existing_provider['startDate'], 'handle': raid_handle }, UpdateExpression="set endDate = :e", ExpressionAttributeValues={ ':e': end_date }, ReturnValues="ALL_NEW" ) return web_helpers.generate_web_body_response('200', { 'name': body['name'], 'startDate': existing_provider['startDate'], 'endDate': end_date }, event) except: logger.error('Unable to end a provider to a RAiD association: {}'.format(sys.exc_info()[0])) return web_helpers.generate_web_body_response('500', { 'message': "Unable to perform request due to error. Please check structure of the body."}, event)