diff --git a/api.saladeaula.digital/app/routes/enrollments/enroll.py b/api.saladeaula.digital/app/routes/enrollments/enroll.py index 14b3692..5c881ae 100644 --- a/api.saladeaula.digital/app/routes/enrollments/enroll.py +++ b/api.saladeaula.digital/app/routes/enrollments/enroll.py @@ -1,7 +1,7 @@ from datetime import date, datetime, time, timedelta from decimal import Decimal from http import HTTPStatus -from typing import Annotated +from typing import Annotated, TypedDict from uuid import uuid4 import pytz @@ -18,7 +18,6 @@ from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair from layercake.extra_types import CpfStr, NameStr from layercake.strutils import md5_hash from pydantic import UUID4, BaseModel, EmailStr, Field, FutureDate -from typing_extensions import TypedDict from boto3clients import dynamodb_client from config import DEDUP_WINDOW_OFFSET_DAYS, ENROLLMENT_TABLE, TZ, USER_TABLE @@ -276,10 +275,13 @@ def enroll_later(enrollment: Enrollment, context: Context): lock_hash = md5_hash(f'{user.id}{course.id}') with dyn.transact_writer() as transact: + pk = f'SCHEDULED#ORG#{org.id}' + sk = f'{scheduled_for.isoformat()}#{lock_hash}' + transact.put( item={ - 'id': f'SCHEDULED#ORG#{org.id}', - 'sk': f'{scheduled_for.isoformat()}#{lock_hash}', + 'id': pk, + 'sk': sk, 'user': user.model_dump(), 'course': course.model_dump(), 'org_name': org.name, @@ -301,6 +303,10 @@ def enroll_later(enrollment: Enrollment, context: Context): item={ 'id': 'LOCK#SCHEDULED', 'sk': lock_hash, + 'scheduled': { + 'id': pk, + 'sk': sk, + }, 'created_at': now_, }, cond_expr='attribute_not_exists(sk)', diff --git a/enrollments-events/app/events/enroll_scheduled.py b/enrollments-events/app/events/enroll_scheduled.py index 38be2fa..76b1710 100644 --- a/enrollments-events/app/events/enroll_scheduled.py +++ b/enrollments-events/app/events/enroll_scheduled.py @@ -6,7 +6,9 @@ from aws_lambda_powertools.utilities.data_classes import ( event_source, ) from aws_lambda_powertools.utilities.typing import LambdaContext +from layercake.dateutils import now from layercake.dynamodb import DynamoDBPersistenceLayer +from layercake.funcs import pick from boto3clients import dynamodb_client from config import ENROLLMENT_TABLE @@ -20,6 +22,8 @@ dyn = DynamoDBPersistenceLayer(ENROLLMENT_TABLE, dynamodb_client) @logger.inject_lambda_context def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool: old_image = event.detail['old_image'] + sk = old_image['sk'] + now_ = now() # Key pattern `SCHEDULED#ORG#{org_id}` *_, org_id = old_image['id'].split('#') offset_days = old_image.get('dedup_window_offset_days') @@ -30,23 +34,52 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool: user=old_image['user'], ) - return enroll( - enrollment, - org={ - 'org_id': org_id, - 'name': old_image['org_name'], - }, - subscription=( - { + try: + enroll( + enrollment, + org={ 'org_id': org_id, - 'billing_day': int(billing_day), + 'name': old_image['org_name'], + }, + subscription=( + { + 'org_id': org_id, + 'billing_day': int(billing_day), + } + if billing_day + else None + ), + created_by=created_by, + scheduled_at=datetime.fromisoformat(old_image['created_at']), + # Transfer the deduplication window if it exists + deduplication_window={'offset_days': offset_days} if offset_days else None, + persistence_layer=dyn, + ) + + keys = ('id', 'name') + dyn.put_item( + item={ + 'id': old_image['id'], + 'sk': f'{sk}#EXECUTED', + 'enrollment_id': enrollment.id, + 'user': pick(keys, old_image['user']), + 'course': pick(keys, old_image['course']), + 'created_by': created_by, + 'created_at': now_, } - if billing_day - else None - ), - created_by=created_by, - scheduled_at=datetime.fromisoformat(old_image['created_at']), - # Transfer the deduplication window if it exists - deduplication_window={'offset_days': offset_days} if offset_days else None, - persistence_layer=dyn, - ) + ) + except Exception as exc: + dyn.put_item( + item={ + 'id': old_image['id'], + 'sk': f'{sk}#FAILED', + 'cause': { + 'type': type(exc).__name__, + 'message': str(exc), + }, + 'snapshot': old_image, + 'created_at': now_, + } + ) + + return True