From 08db9d0191b5ef1093f09296e7cc01f4742a60e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Rafael=20Siqueira?= Date: Tue, 7 Oct 2025 20:07:29 -0300 Subject: [PATCH] add download sample --- api.saladeaula.digital/app/config.py | 2 + .../app/routes/courses/__init__.py | 62 ++++++++++++++++++- api.saladeaula.digital/template.yaml | 2 +- .../tests/routes/test_courses.py | 21 +++++++ enrollments-events/app/events/issue_cert.py | 8 +-- 5 files changed, 87 insertions(+), 8 deletions(-) diff --git a/api.saladeaula.digital/app/config.py b/api.saladeaula.digital/app/config.py index 94932dc..fbf72d5 100644 --- a/api.saladeaula.digital/app/config.py +++ b/api.saladeaula.digital/app/config.py @@ -5,3 +5,5 @@ ENROLLMENT_TABLE: str = os.getenv('ENROLLMENT_TABLE') # type: ignore COURSE_TABLE: str = os.getenv('COURSE_TABLE') # type: ignore BUCKET_NAME: str = os.getenv('BUCKET_NAME') # type: ignore + +PAPERFORGE_API = 'https://paperforge.saladeaula.digital' diff --git a/api.saladeaula.digital/app/routes/courses/__init__.py b/api.saladeaula.digital/app/routes/courses/__init__.py index d923ab9..2de9013 100644 --- a/api.saladeaula.digital/app/routes/courses/__init__.py +++ b/api.saladeaula.digital/app/routes/courses/__init__.py @@ -1,20 +1,24 @@ +import json +from datetime import datetime from http import HTTPStatus from io import BytesIO -from typing import Any +from typing import Annotated, Any +import requests from aws_lambda_powertools import Logger -from aws_lambda_powertools.event_handler.api_gateway import Router +from aws_lambda_powertools.event_handler.api_gateway import Response, Router from aws_lambda_powertools.event_handler.exceptions import ( BadRequestError, NotFoundError, ) +from aws_lambda_powertools.event_handler.openapi.params import Body from layercake.dateutils import now from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair from pydantic import UUID4, BaseModel from api_gateway import JSONResponse from boto3clients import dynamodb_client, s3_client -from config import BUCKET_NAME, COURSE_TABLE +from config import BUCKET_NAME, COURSE_TABLE, PAPERFORGE_API from form_data import parse logger = Logger(__name__) @@ -89,3 +93,55 @@ def edit_course(course_id: str): ) return JSONResponse(HTTPStatus.NO_CONTENT) + + +@router.post('//sample') +def sample(course_id: str, s3_uri: Annotated[str, Body(embed=True)]): + now_ = now() + # Send template URI and data to Paperforge API to generate a PDF + r = requests.post( + PAPERFORGE_API, + data=json.dumps( + { + 'template_uri': s3_uri, + 'args': { + 'name': 'Juscelino Kubitschek', + 'cpf': '***.810.132-**', + 'score': 100, + 'started_at': now_.strftime('%d/%m/%Y'), + 'completed_at': now_.strftime('%d/%m/%Y'), + 'today': _datefmt(now_), + 'year': now_.strftime('%Y'), + 'expires_at': now_.strftime('%d/%m/%Y'), + }, + }, + ), + ) + r.raise_for_status() + + return Response( + body=r.content, + content_type='application/pdf', + status_code=HTTPStatus.OK, + headers={ + 'Content-Disposition': f'attachment; filename="{course_id}_sample.pdf"', + }, + ) + + +def _datefmt(dt: datetime) -> str: + months = [ + 'Janeiro', + 'Fevereiro', + 'Março', + 'Abril', + 'Maio', + 'Junho', + 'Julho', + 'Agosto', + 'Setembro', + 'Outubro', + 'Novembro', + 'Dezembro', + ] + return f'{dt.day:02d} de {months[dt.month - 1]} de {dt.year}' diff --git a/api.saladeaula.digital/template.yaml b/api.saladeaula.digital/template.yaml index ece0d8f..956e38a 100644 --- a/api.saladeaula.digital/template.yaml +++ b/api.saladeaula.digital/template.yaml @@ -70,7 +70,7 @@ Resources: TableName: !Ref CourseTable - DynamoDBCrudPolicy: TableName: !Ref EnrollmentTable - - S3WritePolicy: + - S3CrudPolicy: BucketName: !Ref BucketName Events: Preflight: diff --git a/api.saladeaula.digital/tests/routes/test_courses.py b/api.saladeaula.digital/tests/routes/test_courses.py index 924a4cf..1960eae 100644 --- a/api.saladeaula.digital/tests/routes/test_courses.py +++ b/api.saladeaula.digital/tests/routes/test_courses.py @@ -62,3 +62,24 @@ def test_edit_course( r['cert']['s3_uri'] == 's3://saladeaula.digital/certs/2a8963fc-4694-4fe2-953a-316d1b10f1f5.html' ) + + +def test_sample( + app, + seeds, + dynamodb_persistence_layer: DynamoDBPersistenceLayer, + http_api_proxy: HttpApiProxy, + lambda_context: LambdaContext, +): + r = app.lambda_handler( + http_api_proxy( + raw_path='/courses/2a8963fc-4694-4fe2-953a-316d1b10f1f5/sample', + method=HTTPMethod.POST, + body={ + 's3_uri': 's3://saladeaula.digital/certs/samples/cipa-grau-de-risco-1.html', + }, + ), + lambda_context, + ) + assert r['statusCode'] == HTTPStatus.OK + # print(r['body']) diff --git a/enrollments-events/app/events/issue_cert.py b/enrollments-events/app/events/issue_cert.py index b026155..87724b7 100644 --- a/enrollments-events/app/events/issue_cert.py +++ b/enrollments-events/app/events/issue_cert.py @@ -21,7 +21,8 @@ from config import ( ) 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) @@ -31,11 +32,10 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool: now_ = now() enrollment_id = new_image['id'] course_id = new_image['course']['id'] - cert = dyn.collection.get_item( + cert = course_layer.collection.get_item( KeyPair( pk=course_id, sk=SortKey('0', path_spec='cert', rename_key='cert'), - table_name=COURSE_TABLE, ), raise_on_error=False, default=False, @@ -101,7 +101,7 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool: logger.exception(exc) raise - return dyn.update_item( + return enrollment_layer.update_item( key=KeyPair( pk=enrollment_id, sk='0',