This commit is contained in:
2025-10-14 23:38:39 -03:00
parent a7e5a0a528
commit 54c92b3996
11 changed files with 38 additions and 18 deletions

View File

@@ -2,7 +2,7 @@ from abc import ABC
from dataclasses import dataclass
from datetime import timedelta
from enum import Enum
from typing import NotRequired, Self, TypedDict
from typing import NotRequired, TypedDict
from layercake.dateutils import now, ttl
from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair

View File

@@ -9,11 +9,13 @@ from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair, SortKey
from boto3clients import dynamodb_client
from config import (
COURSE_TABLE,
ENROLLMENT_TABLE,
)
logger = Logger(__name__)
dyn = DynamoDBPersistenceLayer(ENROLLMENT_TABLE, dynamodb_client)
enrollment_layer = DynamoDBPersistenceLayer(ENROLLMENT_TABLE, dynamodb_client)
course_layer = DynamoDBPersistenceLayer(COURSE_TABLE, dynamodb_client)
@event_source(data_class=EventBridgeEvent)
@@ -28,7 +30,7 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
# Post-migration: after removing the stopgap file `patch_course_metadata.py`,
# use `access_expires_at` from `new_image`
access_period = int(
dyn.collection.get_item(
course_layer.collection.get_item(
KeyPair(
pk=new_image['course']['id'],
sk=SortKey('0', path_spec='access_period'),
@@ -36,7 +38,7 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
)
)
with dyn.transact_writer() as transact:
with enrollment_layer.transact_writer() as transact:
transact.put(
item={
'id': enrollment_id,

View File

@@ -26,7 +26,7 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
terms = user_layer.get_item(
# Post-migration (users): uncomment the following line
# KeyPair(new_image['org_id'], 'METADATA#BILLING_TERMS'),
KeyPair(new_image['tenant_id'], 'metadata#billing_policy'),
KeyPair(new_image['org_id'], 'metadata#billing_policy'),
)
if not terms:

View File

@@ -48,7 +48,7 @@ class Enrollment(BaseModel):
return super().model_dump(
exclude={
'user': {'email_verified'},
'course': {'cert', 'access_period'},
'course': {'cert'},
},
*args,
**kwargs,

View File

@@ -252,6 +252,8 @@ Resources:
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref EnrollmentTable
- DynamoDBReadPolicy:
TableName: !Ref CourseTable
Events:
DynamoDBEvent:
Type: EventBridgeRule

View File

@@ -1,6 +1,7 @@
import os
USER_TABLE: str = os.getenv('USER_TABLE') # type: ignore
COURSE_TABLE: str = os.getenv('COURSE_TABLE') # type: ignore
ENROLLMENT_TABLE: str = os.getenv('ENROLLMENT_TABLE') # type: ignore
KONVIVA_API_URL: str = os.getenv('KONVIVA_API_URL') # type: ignore

View File

@@ -10,6 +10,12 @@ from layercake.dateutils import now, ttl
from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair, SortKey, TransactKey
from layercake.strutils import md5_hash
from boto3clients import dynamodb_client
from config import COURSE_TABLE
# @TODO Find a better way
course_layer = DynamoDBPersistenceLayer(COURSE_TABLE, dynamodb_client)
def update_progress(
id: str,
@@ -106,11 +112,6 @@ def set_score(
enrollment = dynamodb_persistence_layer.collection.get_items(
TransactKey(id)
+ SortKey('0')
+ SortKey(
sk='METADATA#COURSE',
# Prevent conflicts with `course`
rename_key='metadata__course',
)
+ SortKey(
sk='METADATA#DEDUPLICATION_WINDOW',
path_spec='offset_days',
@@ -119,6 +120,14 @@ def set_score(
)
user_id = enrollment['user']['id']
course_id = glom(enrollment, 'course.id')
exp_interval = course_layer.collection.get_item(
KeyPair(
pk=course_id,
sk=SortKey('0', path_spec='cert.exp_interval'),
),
raise_on_error=False,
default=0,
)
try:
if score >= 70:
@@ -129,9 +138,7 @@ def set_score(
progress=progress,
user_id=user_id,
course_id=course_id,
cert_exp_interval=int(
glom(enrollment, 'metadata__course.cert.exp_interval', default=0)
),
cert_exp_interval=int(exp_interval),
dedup_window_offset_days=int(enrollment['dedup_window_offset_days']),
dynamodb_persistence_layer=dynamodb_persistence_layer,
)

View File

@@ -8,6 +8,9 @@ Parameters:
EnrollmentTable:
Type: String
Default: betaeducacao-prod-enrollments
CourseTable:
Type: String
Default: saladeaula_courses
Globals:
Function:
@@ -27,6 +30,7 @@ Globals:
POWERTOOLS_LOGGER_LOG_EVENT: true
USER_TABLE: !Ref UserTable
ENROLLMENT_TABLE: !Ref EnrollmentTable
COURSE_TABLE: !Ref CourseTable
KONVIVA_API_URL: https://lms.saladeaula.digital
KONVIVA_SECRET_KEY: "{{resolve:ssm:/betaeducacao/konviva/secret_key/str}}"
@@ -58,6 +62,8 @@ Resources:
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref EnrollmentTable
- DynamoDBReadPolicy:
TableName: !Ref CourseTable
Events:
Post:
Type: HttpApi

View File

@@ -18,6 +18,7 @@ def pytest_configure():
os.environ['DYNAMODB_PARTITION_KEY'] = PK
os.environ['DYNAMODB_SORT_KEY'] = SK
os.environ['USER_TABLE'] = PYTEST_TABLE_NAME
os.environ['COURSE_TABLE'] = PYTEST_TABLE_NAME
os.environ['ENROLLMENT_TABLE'] = PYTEST_TABLE_NAME
os.environ['KONVIVA_API_URL'] = 'https://lms.saladeaula.digital'

View File

@@ -1,6 +1,10 @@
// Users
{"id": "123", "sk": "0"}
// Courses
{"id": "432", "sk": "0", "access_period": 360, "cert": {"exp_interval": 365}, "created_at": "2025-04-06T11:07:32.762178-03:00"}
// Enrollments
{"id": "197991aa-52e2-4e0c-b2a4-a7c53bcfee02", "sk": "0", "progress": 10, "status": "IN_PROGRESS"}
@@ -11,18 +15,15 @@
{"id": "d9da85f2-e09f-472d-9515-3d91d70f1e8a", "sk": "SCHEDULE#REMINDER_NO_ACCESS_AFTER_3_DAYS"}
{"id": "6c7e3d9b-f5d1-4da4-9e55-0825bb6ff2b8", "sk": "0", "progress": 80, "status": "IN_PROGRESS", "user": {"id": "123", "name": "Myles Kennedy"}, "course": {"id": "432", "name": "pytest"}, "created_at": "2022-04-06T11:07:32.762178-03:00"}
{"id": "6c7e3d9b-f5d1-4da4-9e55-0825bb6ff2b8", "sk": "METADATA#COURSE", "access_period": 360, "cert": {"exp_interval": 365}, "created_at": "2025-04-06T11:07:32.762178-03:00"}
{"id": "6c7e3d9b-f5d1-4da4-9e55-0825bb6ff2b8", "sk": "METADATA#DEDUPLICATION_WINDOW", "offset_days": 90, "created_at": "2025-04-06T11:07:32.762178-03:00"}
{"id": "6c7e3d9b-f5d1-4da4-9e55-0825bb6ff2b8", "sk": "SCHEDULE#REMINDER_ACCESS_PERIOD_BEFORE_30_DAYS"}
{"id": "6c7e3d9b-f5d1-4da4-9e55-0825bb6ff2b8", "sk": "SCHEDULE#SET_ACCESS_EXPIRED"}
{"id": "cc2c3bce-c34a-4e82-aa6c-1a19e70ec5ae", "sk": "0", "progress": 109, "status": "COMPLETED", "user": {"id": "321", "name": "Chester Bennington"}, "course": {"id": "432", "name": "pytest"}, "created_at": "2022-04-06T11:07:32.762178-03:00"}
{"id": "cc2c3bce-c34a-4e82-aa6c-1a19e70ec5ae", "sk": "METADATA#COURSE", "access_period": 360, "cert": {"exp_interval": 365}, "created_at": "2025-04-06T11:07:32.762178-03:00"}
{"id": "cc2c3bce-c34a-4e82-aa6c-1a19e70ec5ae", "sk": "METADATA#DEDUPLICATION_WINDOW", "offset_days": 90, "created_at": "2025-04-06T11:07:32.762178-03:00"}
{"id": "cc2c3bce-c34a-4e82-aa6c-1a19e70ec5ae", "sk": "SCHEDULE#SET_AS_ARCHIVED"}
{"id": "5db53b35-0bae-4907-afda-a213cb5bf651", "sk": "0", "progress": 0, "status": "PENDING", "user": {"id": "1234", "name": "Michael Jackinson"}, "course": {"id": "432", "name": "pytest"}, "created_at": "2022-04-06T11:07:32.762178-03:00"}
{"id": "5db53b35-0bae-4907-afda-a213cb5bf651", "sk": "METADATA#COURSE", "access_period": 360, "cert": {"exp_interval": 365}, "created_at": "2025-04-06T11:07:32.762178-03:00"}
// To relate with the enrollment
{"id": "konviva", "sk": "123", "enrollment_id": "d9da85f2-e09f-472d-9515-3d91d70f1e8a"}

View File

@@ -113,7 +113,7 @@ def test_set_as_completed(
docx = next((x for x in r['items'] if x['sk'] == '0'), {})
assert 'completed_at' in docx
assert len(r['items']) == 7
assert len(r['items']) == 6
assert any(item.get('sk') == 'LOCK' for item in r['items'])
assert any(
item.get('sk') == 'SCHEDULE#REMINDER_CERT_EXPIRATION_BEFORE_30_DAYS'