from uuid import uuid4 from aws_lambda_powertools import Logger from aws_lambda_powertools.utilities.data_classes import ( EventBridgeEvent, event_source, ) from aws_lambda_powertools.utilities.typing import LambdaContext from layercake.batch import BatchProcessor from layercake.dateutils import now from layercake.dynamodb import ( DynamoDBPersistenceLayer, KeyChain, KeyPair, SortKey, TransactKey, ) from boto3clients import dynamodb_client from config import COURSE_TABLE, ENROLLMENT_TABLE, ORDER_TABLE from enrollment import ( Course, Enrollment, User, enroll, ) logger = Logger(__name__) order_layer = DynamoDBPersistenceLayer(ORDER_TABLE, dynamodb_client) course_layer = DynamoDBPersistenceLayer(COURSE_TABLE, dynamodb_client) enrollment_layer = DynamoDBPersistenceLayer(ENROLLMENT_TABLE, dynamodb_client) processor = BatchProcessor() @event_source(data_class=EventBridgeEvent) @logger.inject_lambda_context def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool: new_image = event.detail['new_image'] order = order_layer.collection.get_items( TransactKey(new_image['id']) + SortKey('0') + SortKey('items', path_spec='items'), ) items = { item['id']: int(item['quantity']) for item in order['items'] # Ignore items with non-positive unit price; # negative values are treated as discounts if item['unit_price'] > 0 } courses = _get_courses(set(items.keys())) user = User( id=order['user_id'], name=order['name'], email=order['email'], cpf=order['cpf'], ) with processor( records=courses, handler=_handler, context={ 'user': user, 'order_id': new_image['id'], }, ) as batch: result = batch.process() logger.debug('Processed courses', result=result) return order_layer.update_item( key=KeyPair(new_image['id'], new_image['sk']), update_expr='SET #status = :status, updated_at = :updated_at', expr_attr_names={ '#status': 'status', }, expr_attr_values={ ':status': 'SUCCESS', ':updated_at': now(), }, cond_expr='attribute_exists(sk)', ) def _handler(course: Course, context: dict) -> Enrollment: enrollment = Enrollment( id=uuid4(), user=context['user'], course=course, ) enroll(enrollment, persistence_layer=enrollment_layer) return enrollment def _get_courses(ids: set) -> tuple[Course, ...]: pairs = tuple(KeyPair(idx, '0') for idx in ids) result = course_layer.collection.get_items( KeyChain(pairs), flatten_top=False, ) return tuple(Course(id=idx, **obj) for idx, obj in result.items()) # type: ignore