diff --git a/enrollment-management/app/config.py b/enrollment-management/app/config.py index e0334d7..9aff6e7 100644 --- a/enrollment-management/app/config.py +++ b/enrollment-management/app/config.py @@ -3,4 +3,14 @@ import os USER_TABLE: str = os.getenv('USER_TABLE') # type: ignore ORDER_TABLE: str = os.getenv('ORDER_TABLE') # type: ignore ENROLLMENT_TABLE: str = os.getenv('ENROLLMENT_TABLE') # type: ignore -NEW_ENROLLMENT_TABLE: str = os.getenv('NEW_ENROLLMENT_TABLE') # type: ignore +COURSE_TABLE: str = os.getenv('COURSE_TABLE') # type: ignore + + +# Post-migration: remove the lines below +if os.getenv('AWS_LAMBDA_FUNCTION_NAME'): + SQLITE_DATABASE = 'courses_export_2025-06-18_110214.db' +else: + SQLITE_DATABASE = 'app/courses_export_2025-06-18_110214.db' + +SQLITE_TABLE = 'courses' +OLD_ENROLLMENT_TABLE: str = os.getenv('OLD_ENROLLMENT_TABLE') # type: ignore diff --git a/enrollment-management/app/events/emails/__init__.py b/enrollment-management/app/events/emails/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/enrollment-management/app/events/emails/access_period_reminder_30_days.py b/enrollment-management/app/events/emails/access_period_reminder_30_days.py deleted file mode 100644 index da1a33f..0000000 --- a/enrollment-management/app/events/emails/access_period_reminder_30_days.py +++ /dev/null @@ -1,14 +0,0 @@ -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 - -logger = Logger(__name__) - - -@event_source(data_class=EventBridgeEvent) -@logger.inject_lambda_context -def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> None: - """Send an email when the access period expires""" diff --git a/enrollment-management/app/events/emails/cert_expiration_reminder_30_days.py b/enrollment-management/app/events/emails/cert_expiration_reminder_30_days.py deleted file mode 100644 index 85c9a1c..0000000 --- a/enrollment-management/app/events/emails/cert_expiration_reminder_30_days.py +++ /dev/null @@ -1,13 +0,0 @@ -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 - -logger = Logger(__name__) - - -@event_source(data_class=EventBridgeEvent) -@logger.inject_lambda_context -def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> None: ... diff --git a/enrollment-management/app/events/emails/no_activity_7_days.py b/enrollment-management/app/events/emails/no_activity_7_days.py deleted file mode 100644 index f6a1953..0000000 --- a/enrollment-management/app/events/emails/no_activity_7_days.py +++ /dev/null @@ -1,14 +0,0 @@ -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 - -logger = Logger(__name__) - - -@event_source(data_class=EventBridgeEvent) -@logger.inject_lambda_context -def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> None: - """Send an email when there is no activity 7 days after the first access""" diff --git a/enrollment-management/app/events/emails/reminder_no_access_3_days.py b/enrollment-management/app/events/emails/reminder_no_access_3_days.py deleted file mode 100644 index 6c8368b..0000000 --- a/enrollment-management/app/events/emails/reminder_no_access_3_days.py +++ /dev/null @@ -1,14 +0,0 @@ -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 - -logger = Logger(__name__) - - -@event_source(data_class=EventBridgeEvent) -@logger.inject_lambda_context -def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> None: - """Send reminder email if the user does not access within 3 days""" diff --git a/enrollment-management/app/events/set_status_as_archived.py b/enrollment-management/app/events/set_status_as_archived.py deleted file mode 100644 index 0b9eda2..0000000 --- a/enrollment-management/app/events/set_status_as_archived.py +++ /dev/null @@ -1,45 +0,0 @@ -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.dateutils import now -from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair - -from boto3clients import dynamodb_client -from config import ENROLLMENT_TABLE - -logger = Logger(__name__) -enrollment_layer = DynamoDBPersistenceLayer(ENROLLMENT_TABLE, dynamodb_client) - - -@event_source(data_class=EventBridgeEvent) -@logger.inject_lambda_context -def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool: - new_image = event.detail['new_image'] - now_ = now() - - with enrollment_layer.transact_writer() as transact: - transact.update( - key=KeyPair(new_image['id'], '0'), - update_expr='SET #status = :archived, update_date = :update_date', - cond_expr='#status = :completed', - expr_attr_names={ - '#status': 'status', - }, - expr_attr_values={ - ':archived': 'ARCHIVED', - ':completed': 'COMPLETED', - ':update_date': now_, - }, - ) - transact.put( - item={ - 'id': new_image['id'], - 'sk': 'archived_date', - 'create_date': now_, - }, - ) - - return True diff --git a/enrollment-management/app/events/set_status_as_expired.py b/enrollment-management/app/events/set_status_as_expired.py deleted file mode 100644 index 5f31f02..0000000 --- a/enrollment-management/app/events/set_status_as_expired.py +++ /dev/null @@ -1,46 +0,0 @@ -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.dateutils import now -from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair - -from boto3clients import dynamodb_client -from config import ENROLLMENT_TABLE - -logger = Logger(__name__) -enrollment_layer = DynamoDBPersistenceLayer(ENROLLMENT_TABLE, dynamodb_client) - - -@event_source(data_class=EventBridgeEvent) -@logger.inject_lambda_context -def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool: - new_image = event.detail['new_image'] - now_ = now() - - with enrollment_layer.transact_writer() as transact: - transact.update( - key=KeyPair(new_image['id'], '0'), - update_expr='SET #status = :expired, update_date = :update_date', - cond_expr='#status IN (:pending, :in_progress)', - expr_attr_names={ - '#status': 'status', - }, - expr_attr_values={ - ':expired': 'EXPIRED', - ':pending': 'PENDING', - ':in_progress': 'IN_PROGRESS', - ':update_date': now_, - }, - ) - transact.put( - item={ - 'id': new_image['id'], - 'sk': 'expired_date', - 'create_date': now_, - }, - ) - - return True diff --git a/enrollment-management/app/events/stopgap/delete_vacancies.py b/enrollment-management/app/events/stopgap/delete_vacancies.py deleted file mode 100644 index deaa5eb..0000000 --- a/enrollment-management/app/events/stopgap/delete_vacancies.py +++ /dev/null @@ -1,69 +0,0 @@ -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.dynamodb import ( - ComposeKey, - DynamoDBPersistenceLayer, - KeyPair, - SortKey, - TransactKey, -) - -from boto3clients import dynamodb_client -from config import ENROLLMENT_TABLE, ORDER_TABLE, USER_TABLE - -logger = Logger(__name__) -user_layer = DynamoDBPersistenceLayer(USER_TABLE, dynamodb_client) -order_layer = DynamoDBPersistenceLayer(ORDER_TABLE, dynamodb_client) -enrollment_layer = DynamoDBPersistenceLayer(ENROLLMENT_TABLE, dynamodb_client) - - -@event_source(data_class=EventBridgeEvent) -@logger.inject_lambda_context -def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool: - new_image = event.detail['new_image'] - order_id = new_image['id'] - data = order_layer.collection.get_items( - TransactKey(order_id) - + SortKey('0') - + KeyPair( - pk=order_id, - sk=SortKey( - sk='metadata#tenant', - path_spec='tenant_id', - remove_prefix='metadata#', - ), - rename_key='tenant_id', - ) - ) - total = data['total'] - tenant_id = data['tenant_id'].removeprefix('ORG#') - - policy = user_layer.collection.get_item( - KeyPair(pk=tenant_id, sk='metadata#billing_policy'), - raise_on_error=False, - default=False, - ) - - if not policy or total <= 0: - return False - - result = enrollment_layer.collection.query( - KeyPair( - ComposeKey(tenant_id, prefix='vacancies'), - order_id, - ) - ) - with enrollment_layer.batch_writer() as batch: - for pair in result['items']: - batch.delete_item( - Key={ - 'id': {'S': ComposeKey(pair['id'], prefix='vacancies')}, - 'sk': {'S': pair['sk']}, - } - ) - - return True diff --git a/enrollment-management/app/events/stopgap/enroll.py b/enrollment-management/app/events/stopgap/enroll.py index e13be09..e53e0eb 100644 --- a/enrollment-management/app/events/stopgap/enroll.py +++ b/enrollment-management/app/events/stopgap/enroll.py @@ -1,14 +1,59 @@ +import json +import sqlite3 + 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.dynamodb import DynamoDBPersistenceLayer +from sqlite_utils import Database + +from boto3clients import dynamodb_client +from config import ( + COURSE_TABLE, + ENROLLMENT_TABLE, + SQLITE_DATABASE, + SQLITE_TABLE, +) + +sqlite3.register_converter('json', json.loads) logger = Logger(__name__) +enrollment_layer = DynamoDBPersistenceLayer(ENROLLMENT_TABLE, dynamodb_client) +course_layer = DynamoDBPersistenceLayer(COURSE_TABLE, dynamodb_client) +deduplication_window = {'offset_days': 90} + + +class DeduplicationConflictError(Exception): + def __init__(self, *args): + super().__init__('Enrollment already exists') @event_source(data_class=EventBridgeEvent) @logger.inject_lambda_context def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool: + new_image = event.detail['new_image'] + return True + + +class CourseNotFoundError(Exception): + def __init__(self, *args): + super().__init__('Course not found') + + +def _get_course(course_id: str) -> dict: + with sqlite3.connect( + database=SQLITE_DATABASE, detect_types=sqlite3.PARSE_DECLTYPES + ) as conn: + db = Database(conn) + rows = db[SQLITE_TABLE].rows_where( + "json->>'$.metadata__betaeducacao_id' = ?", [course_id] + ) + + for row in rows: + return row['json'] + + raise CourseNotFoundError diff --git a/enrollment-management/template.yaml b/enrollment-management/template.yaml index 60bbef7..67ad678 100644 --- a/enrollment-management/template.yaml +++ b/enrollment-management/template.yaml @@ -8,9 +8,9 @@ Parameters: EnrollmentTable: Type: String Default: betaeducacao-prod-enrollments - NewEnrollmentTable: + CourseTable: Type: String - Default: saladeaula_enrollments + Default: saladeaula_courses OrderTable: Type: String Default: betaeducacao-prod-orders @@ -23,7 +23,7 @@ Globals: Architectures: - x86_64 Layers: - - !Sub arn:aws:lambda:sa-east-1:336641857101:layer:layercake:75 + - !Sub arn:aws:lambda:sa-east-1:336641857101:layer:layercake:78 Environment: Variables: TZ: America/Sao_Paulo @@ -34,6 +34,7 @@ Globals: USER_TABLE: !Ref UserTable ENROLLMENT_TABLE: !Ref EnrollmentTable ORDER_TABLE: !Ref OrderTable + COURSE_TABLE: !Ref CourseTable Resources: EventLog: @@ -49,8 +50,6 @@ Resources: LogGroup: !Ref EventLog Policies: - DynamoDBCrudPolicy: - TableName: !Ref NewEnrollmentTable - - DynamoDBReadPolicy: TableName: !Ref EnrollmentTable Events: DynamoDBEvent: @@ -61,68 +60,4 @@ Resources: detail-type: [INSERT] detail: new_image: - sk: ["0"] - - EventDeleteVacanciesFunction: - Type: AWS::Serverless::Function - Properties: - Handler: events.stopgap.delete_vacancies.lambda_handler - LoggingConfig: - LogGroup: !Ref EventLog - Policies: - - DynamoDBReadPolicy: - TableName: !Ref UserTable - - DynamoDBReadPolicy: - TableName: !Ref OrderTable - - DynamoDBCrudPolicy: - TableName: !Ref EnrollmentTable - Events: - DynamoDBEvent: - Type: EventBridgeRule - Properties: - Pattern: - resources: [!Ref OrderTable] - detail: - new_image: - sk: [generated_items] - status: [SUCCESS] - - EventSetStatusAsArchivedFunction: - Type: AWS::Serverless::Function - Properties: - Handler: events.set_status_as_archived.lambda_handler - LoggingConfig: - LogGroup: !Ref EventLog - Policies: - - DynamoDBWritePolicy: - TableName: !Ref EnrollmentTable - Events: - DynamoDBEvent: - Type: EventBridgeRule - Properties: - Pattern: - resources: [!Ref EnrollmentTable] - detail-type: [EXPIRE] - detail: - keys: - sk: [schedules#course_archived] - - EventSetStatusAsExpiredFunction: - Type: AWS::Serverless::Function - Properties: - Handler: events.set_status_as_expired.lambda_handler - LoggingConfig: - LogGroup: !Ref EventLog - Policies: - - DynamoDBWritePolicy: - TableName: !Ref EnrollmentTable - Events: - DynamoDBEvent: - Type: EventBridgeRule - Properties: - Pattern: - resources: [!Ref EnrollmentTable] - detail-type: [EXPIRE] - detail: - keys: - sk: [schedules#course_expired] + sk: ["konviva"] diff --git a/enrollment-management/tests/conftest.py b/enrollment-management/tests/conftest.py index f4e9815..9bd2934 100644 --- a/enrollment-management/tests/conftest.py +++ b/enrollment-management/tests/conftest.py @@ -18,6 +18,8 @@ def pytest_configure(): os.environ['COURSE_TABLE'] = PYTEST_TABLE_NAME os.environ['ORDER_TABLE'] = PYTEST_TABLE_NAME os.environ['ENROLLMENT_TABLE'] = PYTEST_TABLE_NAME + # Post-migration: remove it + os.environ['OLD_ENROLLMENT_TABLE'] = PYTEST_TABLE_NAME @dataclass diff --git a/enrollment-management/tests/events/stopgap/test_delete_vacancies.py b/enrollment-management/tests/events/stopgap/test_delete_vacancies.py deleted file mode 100644 index 14534cc..0000000 --- a/enrollment-management/tests/events/stopgap/test_delete_vacancies.py +++ /dev/null @@ -1,30 +0,0 @@ -from layercake.dynamodb import PartitionKey - -import events.stopgap.delete_vacancies as app - -from ...conftest import LambdaContext - - -def test_del_vacancies( - dynamodb_seeds, - dynamodb_persistence_layer, - lambda_context: LambdaContext, -): - event = { - 'detail': { - 'new_image': { - 'id': '9omWNKymwU5U4aeun6mWzZ', - 'sk': 'generated_items', - 'create_date': '2024-07-23T20:43:37.303418-03:00', - 'status': 'SUCCESS', - 'scope': 'MILTI_USER', - } - }, - } - assert app.lambda_handler(event, lambda_context) # type: ignore - - result = dynamodb_persistence_layer.collection.query( - PartitionKey('vacancies#cJtK9SsnJhKPyxESe7g3DG') - ) - - assert len(result['items']) == 0 diff --git a/enrollment-management/tests/events/stopgap/test_enroll.py b/enrollment-management/tests/events/stopgap/test_enroll.py new file mode 100644 index 0000000..bbfe0cd --- /dev/null +++ b/enrollment-management/tests/events/stopgap/test_enroll.py @@ -0,0 +1,39 @@ +import pprint + +import app.events.stopgap.enroll as app +from aws_lambda_powertools.utilities.typing import LambdaContext +from layercake.dynamodb import ( + DynamoDBPersistenceLayer, + SortKey, + TransactKey, +) + + +def test_enroll( + dynamodb_seeds, + dynamodb_client, + dynamodb_persistence_layer: DynamoDBPersistenceLayer, + lambda_context: LambdaContext, +): + event = { + 'detail': { + 'new_image': { + 'id': '47ZxxcVBjvhDS5TE98tpfQ', + 'sk': 'konviva', + } + } + } + assert app.lambda_handler(event, lambda_context) # type: ignore + + result = dynamodb_persistence_layer.collection.get_items( + TransactKey('47ZxxcVBjvhDS5TE98tpfQ') + + SortKey('0') + + SortKey('metadata#tenant') + + SortKey('metadata#author') + + SortKey('metadata#konviva') + + SortKey('metadata#lock') + + SortKey('metadata#deduplication_window') + + SortKey('metadata#cert') + ) + + pprint.pprint(result) diff --git a/enrollment-management/tests/seeds.jsonl b/enrollment-management/tests/seeds.jsonl index 81754ce..59f636b 100644 --- a/enrollment-management/tests/seeds.jsonl +++ b/enrollment-management/tests/seeds.jsonl @@ -1,8 +1,3 @@ -{"id": {"S": "cJtK9SsnJhKPyxESe7g3DG"}, "sk": {"S": "metadata#payment_policy"}, "due_days": {"N": "90"}} -{"id": {"S": "cJtK9SsnJhKPyxESe7g3DG"}, "sk": {"S": "metadata#billing_policy"}, "billing_day": {"N": "1"}, "payment_method": {"S": "PIX"}} -{"id": {"S": "9omWNKymwU5U4aeun6mWzZ"}, "sk": {"S": "0"}, "total": {"N": "398"}} -{"id": {"S": "9omWNKymwU5U4aeun6mWzZ"}, "sk": {"S": "metadata#tenant"}, "tenant_id": {"S": "ORG#cJtK9SsnJhKPyxESe7g3DG"}} -{"id": {"S": "9omWNKymwU5U4aeun6mWzZ"}, "sk": {"S": "metadata#tenant"}, "tenant_id": {"S": "ORG#cJtK9SsnJhKPyxESe7g3DG"}} -{"id": {"S": "vacancies#cJtK9SsnJhKPyxESe7g3DG"}, "sk": {"S": "9omWNKymwU5U4aeun6mWzZ#1"}} -{"id": {"S": "vacancies#cJtK9SsnJhKPyxESe7g3DG"}, "sk": {"S": "9omWNKymwU5U4aeun6mWzZ#2"}} -{"id": {"S": "vacancies#cJtK9SsnJhKPyxESe7g3DG"}, "sk": {"S": "9omWNKymwU5U4aeun6mWzZ#3"}} +{"id": {"S": "47ZxxcVBjvhDS5TE98tpfQ"}, "sk": {"S": "0"}, "course": {"M": {"id": {"S": "42"}, "name": {"S": "NR-35 Segurança nos Trabalhos em Altura (Teórico)"},"time_in_days": {"N": "720"}}},"create_date": {"S": "2025-04-10T11:58:33.303347-03:00"},"konviva:id": {"N": "238662"},"progress": {"N": "16.67"},"score": {"NULL": true},"status": {"S": "IN_PROGRESS"}, "update_date": {"S": "2025-04-10T15:44:03.023054-03:00"}, "user": {"M": {"id": {"S": "5OxmMjL-ujoR5IMGegQz"}, "cpf": {"S": "07879819908"}, "email": {"S": "sergio@somosbeta.com.br"}, "name": {"S": "Sérgio Rafael Siqueira"}}}} +{"id": {"S": "47ZxxcVBjvhDS5TE98tpfQ"}, "sk": {"S": "konviva"}, "create_date": {"S": "2025-04-10T11:58:35.035729-03:00"}, "konviva_id": {"N": "238662"}} +{"id": {"S": "47ZxxcVBjvhDS5TE98tpfQ"}, "sk": {"S": "tenant"}, "create_date": {"S": "2025-04-10T11:58:33.303347-03:00"}, "name": {"S": "Beta Educação"},"org_id": {"S": "cJtK9SsnJhKPyxESe7g3DG"}} \ No newline at end of file diff --git a/enrollment-management/uv.lock b/enrollment-management/uv.lock index 10b9ce1..96dba15 100644 --- a/enrollment-management/uv.lock +++ b/enrollment-management/uv.lock @@ -221,6 +221,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, ] +[[package]] +name = "click" +version = "8.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, +] + +[[package]] +name = "click-default-group" +version = "1.2.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1d/ce/edb087fb53de63dad3b36408ca30368f438738098e668b78c87f93cd41df/click_default_group-1.2.4.tar.gz", hash = "sha256:eb3f3c99ec0d456ca6cd2a7f08f7d4e91771bef51b01bdd9580cc6450fe1251e", size = 3505, upload-time = "2023-08-04T07:54:58.425Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/1a/aff8bb287a4b1400f69e09a53bd65de96aa5cee5691925b38731c67fc695/click_default_group-1.2.4-py2.py3-none-any.whl", hash = "sha256:9b60486923720e7fc61731bdb32b617039aba820e22e1c88766b1125592eaa5f", size = 4123, upload-time = "2023-08-04T07:54:56.875Z" }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -522,7 +546,7 @@ wheels = [ [[package]] name = "layercake" -version = "0.6.5" +version = "0.6.9" source = { directory = "../layercake" } dependencies = [ { name = "arnparse" }, @@ -539,6 +563,7 @@ dependencies = [ { name = "pytz" }, { name = "requests" }, { name = "smart-open", extra = ["s3"] }, + { name = "sqlite-utils" }, { name = "weasyprint" }, ] @@ -558,6 +583,7 @@ requires-dist = [ { name = "pytz", specifier = ">=2025.1" }, { name = "requests", specifier = ">=2.32.3" }, { name = "smart-open", extras = ["s3"], specifier = ">=7.1.0" }, + { name = "sqlite-utils", specifier = ">=3.38" }, { name = "weasyprint", specifier = ">=65.0" }, ] @@ -911,6 +937,41 @@ s3 = [ { name = "boto3" }, ] +[[package]] +name = "sqlite-fts4" +version = "1.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c2/6d/9dad6c3b433ab8912ace969c66abd595f8e0a2ccccdb73602b1291dbda29/sqlite-fts4-1.0.3.tar.gz", hash = "sha256:78b05eeaf6680e9dbed8986bde011e9c086a06cb0c931b3cf7da94c214e8930c", size = 9718, upload-time = "2022-07-30T01:14:26.943Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/29/0096e8b1811aaa78cfb296996f621f41120c21c2f5cd448ae1d54979d9fc/sqlite_fts4-1.0.3-py3-none-any.whl", hash = "sha256:0359edd8dea6fd73c848989e1e2b1f31a50fe5f9d7272299ff0e8dbaa62d035f", size = 9972, upload-time = "2022-07-30T01:14:24.942Z" }, +] + +[[package]] +name = "sqlite-utils" +version = "3.38" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "click-default-group" }, + { name = "pluggy" }, + { name = "python-dateutil" }, + { name = "sqlite-fts4" }, + { name = "tabulate" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/51/43/ce9183a21911e0b73248c8fb83f8b8038515cb80053912c2a009e9765564/sqlite_utils-3.38.tar.gz", hash = "sha256:1ae77b931384052205a15478d429464f6c67a3ac3b4eafd3c674ac900f623aab", size = 214449, upload-time = "2024-11-23T22:49:40.308Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/eb/f8e8e827805f810838efff3311cccd2601238c5fa3fc35c1f878709e161b/sqlite_utils-3.38-py3-none-any.whl", hash = "sha256:8a27441015c3b2ef475f555861f7a2592f73bc60d247af9803a11b65fc605bf9", size = 68183, upload-time = "2024-11-23T22:49:38.289Z" }, +] + +[[package]] +name = "tabulate" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/fe/802052aecb21e3797b8f7902564ab6ea0d60ff8ca23952079064155d1ae1/tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", size = 81090, upload-time = "2022-10-06T17:21:48.54Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252, upload-time = "2022-10-06T17:21:44.262Z" }, +] + [[package]] name = "tinycss2" version = "1.4.0" diff --git a/http-api/uv.lock b/http-api/uv.lock index ff26028..aed8f25 100644 --- a/http-api/uv.lock +++ b/http-api/uv.lock @@ -586,7 +586,7 @@ wheels = [ [[package]] name = "layercake" -version = "0.6.5" +version = "0.6.11" source = { directory = "../layercake" } dependencies = [ { name = "arnparse" }, @@ -603,6 +603,7 @@ dependencies = [ { name = "pytz" }, { name = "requests" }, { name = "smart-open", extra = ["s3"] }, + { name = "sqlite-utils" }, { name = "weasyprint" }, ] @@ -622,6 +623,7 @@ requires-dist = [ { name = "pytz", specifier = ">=2025.1" }, { name = "requests", specifier = ">=2.32.3" }, { name = "smart-open", extras = ["s3"], specifier = ">=7.1.0" }, + { name = "sqlite-utils", specifier = ">=3.38" }, { name = "weasyprint", specifier = ">=65.0" }, ] diff --git a/order-management/template.yaml b/order-management/template.yaml index ffe58be..36f8a64 100644 --- a/order-management/template.yaml +++ b/order-management/template.yaml @@ -64,32 +64,6 @@ Resources: metadata__tenant_id: - exists: false - EventAssignTenantCpfFunction: - Type: AWS::Serverless::Function - Properties: - Handler: events.assign_tenant_cpf.lambda_handler - LoggingConfig: - LogGroup: !Ref EventLog - Policies: - - DynamoDBCrudPolicy: - TableName: !Ref UserTable - - DynamoDBCrudPolicy: - TableName: !Ref OrderTable - Events: - Event: - Type: EventBridgeRule - Properties: - Pattern: - resources: [!Ref OrderTable] - detail-type: [INSERT] - detail: - new_image: - sk: ["0"] - cpf: - - exists: true - metadata__tenant_id: - - exists: false - EventRemoveSlotsOnCanceledFunction: Type: AWS::Serverless::Function Properties: