async def handler(values=None, **kwargs): try: expire_at = values.timestamp + datetime.timedelta( seconds=int(values.expire)) except Exception: return 400, {'error': 'Invalid value for expire'} try: stored_data = await load('user', values.prompt_user_hash) if stored_data: if stored_data.get('state') in ('pending', 'received') and not is_expired( stored_data.get('expireAt')): return 406, {'error': 'Prompt already pending'} if values.encrypted_data and sha3( stored_data.get('encryptedData')) == sha3( values.encrypted_data): return 406, {'error': 'Prompt already sent'} except Exception: pass prompt_identifier = str(uuid.uuid4()) store_data = { 'promptIdentifier': prompt_identifier, 'promptUserHash': values.prompt_user_hash, 'uniqueIdentifier': str(uuid.uuid4()), 'state': 'pending', 'encryptedData': values.encrypted_data, 'timestamp': values.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ'), 'expireAt': expire_at.strftime('%Y-%m-%dT%H:%M:%S.%fZ'), 'respondedAt': None, 'responseHash': None } await store('prompt', prompt_identifier, store_data) await store('user', values.prompt_user_hash, store_data) subscription_data = await load('subscription', values.prompt_user_hash) # noqa if subscription_data and isinstance(subscription_data, list): for subscription in subscription_data: if subscription.get('promptUserHash') == values.prompt_user_hash: # todo send notification pass return 200, { 'promptIdentifier': prompt_identifier, 'state': store_data.get('state'), 'expireAt': store_data.get('expireAt') }
async def _load_s3(file_type, identifier, decode=True): client = _get_s3_client() try: object_data = await async_call(client.get_object( Bucket=settings.aws_s3_bucket, Key='{}/{}'.format(file_type, sha3(identifier)) )) except botocore.exceptions.ClientError as e: if e.response['Error']['Code'] == 'NoSuchKey': return None if e.response['Error']['Code'] == 'AccessDenied': return None else: raise e data = await async_call(object_data.get('Body').read()) if data: data = decrypt(data, identifier) try: if data and decode: return json.loads(data) except Exception: pass return data
async def _store_s3(file_type, identifier, data, save_previous=False): client = _get_s3_client() key = '{}/{}'.format(file_type, sha3(identifier)) if isinstance(data, str): data = data.encode('utf-8') if not isinstance(data, bytes): data = json.dumps(data).encode() if save_previous: try: await async_call(client.copy_object( Bucket=settings.aws_s3_bucket, Key=f'{key}.previousver', CopySource={'Bucket': settings.aws_s3_bucket, 'Key': key} )) except botocore.exceptions.ClientError as e: if e.response['Error']['Code'] == 'NoSuchKey': pass if e.response['Error']['Code'] == 'AccessDenied': pass else: raise e if data: data = encrypt(data, identifier) await async_call(client.put_object( Bucket=settings.aws_s3_bucket, Key=key, Body=data ))
async def _delete_local(file_type, identifier, delete_previous=False): file_path = os.path.join(settings.data_path, file_type, sha3(identifier)) if os.path.isfile(file_path): os.remove(file_path) if delete_previous: previousver_file_path = f'{file_path}.previousver' if os.path.isfile(previousver_file_path): os.remove(previousver_file_path)
async def _delete_s3(file_type, identifier, delete_previous=False): client = _get_s3_client() key = '{}/{}'.format(file_type, sha3(identifier)) await async_call(client.delete_object( Bucket=settings.aws_s3_bucket, Key=key )) if delete_previous: await async_call(client.delete_object( Bucket=settings.aws_s3_bucket, Key=f'{key}.previousver' ))
async def _mtime_s3(file_type, identifier, decode=True): client = _get_s3_client() try: object_data = await async_call(client.head_object( # noqa Bucket=settings.aws_s3_bucket, Key='{}/{}'.format(file_type, sha3(identifier)) )) except botocore.exceptions.ClientError as e: if e.response['Error']['Code'] == 'NoSuchKey': return None if e.response['Error']['Code'] == 'AccessDenied': return None else: raise e return None
async def _load_local(file_type, identifier, decode=True): file_path = os.path.join(settings.data_path, file_type, sha3(identifier)) if os.path.isfile(file_path): with open(file_path, 'rb') as file: data = file.read() if data: data = decrypt(data, identifier) try: if data and decode: return json.loads(data) except Exception: pass return data return None
async def _store_local(file_type, identifier, data, save_previous=False): directory = os.path.join(settings.data_path, file_type) file_path = os.path.join(directory, sha3(identifier)) if isinstance(data, str): data = data.encode('utf-8') if not isinstance(data, bytes): data = json.dumps(data).encode() if not os.path.isdir(directory): os.makedirs(directory) if save_previous and os.path.isfile(file_path): shutil.copyfile(file_path, f'{file_path}.previousver') if data: data = encrypt(data, identifier) with open(file_path, 'wb') as file: file.write(data)