fix issued cert

This commit is contained in:
2025-09-22 10:42:13 -03:00
parent 6d352ab3a3
commit 18674d8831
5 changed files with 40 additions and 21 deletions

View File

@@ -0,0 +1,13 @@
"""
If a certificate exists, remind the user that the certificate expired.
"""
SUBJECT = 'Seu certificado {course} expirou!'
MESSAGE = """
Oi {first_name}, tudo bem?<br/><br/>
O certificado do curso <b>{course}</b> expirou.<br/>
Para manter sua certificação válida, é necessário refazer o curso.<br/><br/>
<a href="https://saladeaula.digital">👉 Acesse o curso e renove sua certificação</a>
"""

View File

@@ -15,7 +15,7 @@ from boto3clients import dynamodb_client, s3_client
from config import BUCKET_NAME, ENROLLMENT_TABLE, PAPERFORGE_API from config import BUCKET_NAME, ENROLLMENT_TABLE, PAPERFORGE_API
logger = Logger(__name__) logger = Logger(__name__)
enrollment_layer = DynamoDBPersistenceLayer(ENROLLMENT_TABLE, dynamodb_client) dyn = DynamoDBPersistenceLayer(ENROLLMENT_TABLE, dynamodb_client)
@event_source(data_class=EventBridgeEvent) @event_source(data_class=EventBridgeEvent)
@@ -24,24 +24,23 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
new_image = event.detail['new_image'] new_image = event.detail['new_image']
now_ = now() now_ = now()
enrollment_id = new_image['id'] enrollment_id = new_image['id']
course = enrollment_layer.collection.get_items( cert = dyn.collection.get_item(
TransactKey(new_image['id']) KeyPair(
+ SortKey('METADATA#COURSE', path_spec='cert', rename_key='cert') pk=new_image['id'],
# Post-migration: remove the following lines sk=SortKey('METADATA#COURSE', path_spec='cert', rename_key='cert'),
+ SortKey('STARTED', path_spec='started_at', rename_key='started_at') ),
+ SortKey('COMPLETED', path_spec='completed_at', rename_key='completed_at'), raise_on_error=False,
flatten_top=False, default=False,
) )
if 'cert' not in course: if not cert:
logger.debug('Certificate not found') logger.debug('Certificate not found')
# There is no certificate to issue from metadata # There is no certificate to issue from metadata
return False return False
cert = course['cert'] started_at: datetime = fromisoformat(new_image['started_at']) # type: ignore
started_at: datetime = fromisoformat(course['started_at']) # type: ignore completed_at: datetime = fromisoformat(new_image['completed_at']) # type: ignore
completed_at: datetime = fromisoformat(course['completed_at']) # type: ignore cert_expires_at = completed_at + timedelta(days=int(cert['exp_interval']))
cert_expires_at = now_ + timedelta(days=int(cert['exp_interval']))
try: try:
# Send template URI and data to Paperforge API to generate a PDF # Send template URI and data to Paperforge API to generate a PDF
@@ -83,13 +82,14 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
logger.exception(exc) logger.exception(exc)
raise raise
return enrollment_layer.update_item( return dyn.update_item(
key=KeyPair( key=KeyPair(
pk=enrollment_id, pk=enrollment_id,
sk='0', sk='0',
), ),
update_expr='SET issued_cert = :issued_cert', update_expr='SET issued_cert = :issued_cert, uploaded_at = :now',
expr_attr_values={ expr_attr_values={
':now': now_,
':issued_cert': { ':issued_cert': {
'issued_at': now_, 'issued_at': now_,
'expires_at': cert_expires_at, 'expires_at': cert_expires_at,

View File

@@ -14,6 +14,8 @@ def test_issue_cert(
'detail': { 'detail': {
'new_image': { 'new_image': {
'id': enrollment_id, 'id': enrollment_id,
'completed_at': '2025-09-21T14:20:36.276467-03:00',
'started_at': '2025-09-19T14:34:54.704548-03:00',
'user': { 'user': {
'name': 'Jimi Hendrix', 'name': 'Jimi Hendrix',
'cpf': '74630003037', 'cpf': '74630003037',

View File

@@ -72,8 +72,8 @@ def get_enrollment(id: str):
record = enrollment_layer.collection.get_items( record = enrollment_layer.collection.get_items(
TransactKey(id) TransactKey(id)
+ SortKey('0') + SortKey('0')
+ SortKey('STARTED', rename_key='started_at', path_spec='started_at') # + SortKey('STARTED', rename_key='started_at', path_spec='started_at')
+ SortKey('COMPLETED', rename_key='completed_at', path_spec='completed_at') # + SortKey('COMPLETED', rename_key='completed_at', path_spec='completed_at')
+ SortKey('FAILED', rename_key='failed_at', path_spec='failed_at') + SortKey('FAILED', rename_key='failed_at', path_spec='failed_at')
+ SortKey('CANCELED', rename_key='canceled') + SortKey('CANCELED', rename_key='canceled')
+ SortKey('ARCHIVED', rename_key='archived_at', path_spec='archived_at') + SortKey('ARCHIVED', rename_key='archived_at', path_spec='archived_at')

View File

@@ -201,7 +201,10 @@ def set_status_as_canceled(
with persistence_layer.transact_writer() as transact: with persistence_layer.transact_writer() as transact:
transact.update( transact.update(
key=KeyPair(id, '0'), key=KeyPair(id, '0'),
update_expr='SET #status = :canceled, updated_at = :updated_at', update_expr='SET #status = :canceled, \
access_expired = :true, \
canceled_at = :now, \
updated_at = :now',
cond_expr='#status = :pending', cond_expr='#status = :pending',
expr_attr_names={ expr_attr_names={
'#status': 'status', '#status': 'status',
@@ -209,7 +212,8 @@ def set_status_as_canceled(
expr_attr_values={ expr_attr_values={
':canceled': 'CANCELED', ':canceled': 'CANCELED',
':pending': 'PENDING', ':pending': 'PENDING',
':updated_at': now_, ':true': True,
':now': now_,
}, },
) )
transact.put( transact.put(
@@ -217,7 +221,7 @@ def set_status_as_canceled(
'id': id, 'id': id,
'sk': 'CANCELED', 'sk': 'CANCELED',
'canceled_by': created_by, 'canceled_by': created_by,
'canceled_at': now_, 'created_at': now_,
}, },
) )
transact.delete( transact.delete(
@@ -256,7 +260,7 @@ def set_status_as_canceled(
transact.delete( transact.delete(
key=KeyPair( key=KeyPair(
pk=id, pk=id,
sk='SCHEDULE#SET_AS_EXPIRED', sk='SCHEDULE#SET_ACCESS_EXPIRED',
) )
) )
transact.delete( transact.delete(