update url

This commit is contained in:
2025-10-03 21:58:35 -03:00
parent 5ae2128dee
commit b9ac0f1dae
4 changed files with 85 additions and 30 deletions

View File

@@ -1,4 +1,6 @@
from http import HTTPStatus
from io import BytesIO from io import BytesIO
from typing import Any
from aws_lambda_powertools import Logger 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 Router
@@ -6,12 +8,14 @@ from aws_lambda_powertools.event_handler.exceptions import (
BadRequestError, BadRequestError,
NotFoundError, NotFoundError,
) )
from layercake.dateutils import now
from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair
from pydantic import UUID4, BaseModel from pydantic import UUID4, BaseModel
from python_multipart import parse_form
from api_gateway import JSONResponse
from boto3clients import dynamodb_client from boto3clients import dynamodb_client
from config import COURSE_TABLE from config import COURSE_TABLE
from form_data import parse
logger = Logger(__name__) logger = Logger(__name__)
router = Router() router = Router()
@@ -27,45 +31,53 @@ def get_course(course_id: str):
class Cert(BaseModel): class Cert(BaseModel):
exp_interval: int exp_interval: int | None = None
rawfile: bytes rawfile: bytes | None = None
def model_dump(self, **kwargs) -> dict[str, Any]:
return super().model_dump(
exclude={'rawfile'},
exclude_none=True,
**kwargs,
)
class FormData(BaseModel): class Course(BaseModel):
id: UUID4 id: UUID4
name: str name: str
access_period: int access_period: int
cert: Cert | None = None cert: Cert | None = None
@router.post('/<course_id>') @router.put('/<course_id>')
def edit_course(course_id: str): def edit_course(course_id: str):
event = router.current_event event = router.current_event
if not event.decoded_body: if not event.decoded_body:
raise BadRequestError('Invalid request body') raise BadRequestError('Invalid request body')
ret = {'id': course_id}
body = BytesIO(event.decoded_body.encode()) body = BytesIO(event.decoded_body.encode())
course = Course.model_validate(
def on_field(field): {'id': course_id} | parse(event.headers, body),
field_name = field.field_name.decode().split('.')
if len(field_name) > 1:
field_name, subfield_name = field_name
print(field_name, subfield_name)
else:
field_name, *_ = field_name
ret[field_name] = field.value
parse_form(
event.headers, # type: ignore
body,
on_field=on_field,
on_file=on_field,
) )
now_ = now()
# print(ret.keys()) with dyn.transact_writer() as transact:
data = FormData.model_validate(ret) transact.update(
print(data) key=KeyPair(str(course.id), '0'),
return {} update_expr='SET #name = :name, access_period = :access_period, \
cert = :cert, updated_at = :updated_at',
expr_attr_names={
'#name': 'name',
},
expr_attr_values={
':name': course.name,
':cert': course.cert.model_dump() if course.cert else None,
':access_period': course.access_period,
':updated_at': now_,
},
cond_expr='attribute_exists(sk)',
exc_cls=BadRequestError,
)
return JSONResponse(HTTPStatus.NO_CONTENT)

View File

@@ -1,5 +1,6 @@
from http import HTTPMethod, HTTPStatus from http import HTTPMethod, HTTPStatus
from layercake.dynamodb import DynamoDBPersistenceLayer
from requests_toolbelt import MultipartEncoder from requests_toolbelt import MultipartEncoder
from ..conftest import HttpApiProxy, LambdaContext from ..conftest import HttpApiProxy, LambdaContext
@@ -24,14 +25,17 @@ def test_get_course(
def test_edit_course( def test_edit_course(
app, app,
seeds, seeds,
dynamodb_persistence_layer: DynamoDBPersistenceLayer,
http_api_proxy: HttpApiProxy, http_api_proxy: HttpApiProxy,
lambda_context: LambdaContext, lambda_context: LambdaContext,
): ):
course_id = '2a8963fc-4694-4fe2-953a-316d1b10f1f5'
with open('tests/sample.html', 'rb') as f: with open('tests/sample.html', 'rb') as f:
m = MultipartEncoder( m = MultipartEncoder(
fields={ fields={
'given_cert': 'true', 'given_cert': 'true',
'name': 'pytest', 'name': 'pytest updated from test',
'access_period': '365', 'access_period': '365',
'cert.exp_interval': '360', 'cert.exp_interval': '360',
'cert.rawfile': f, 'cert.rawfile': f,
@@ -39,8 +43,8 @@ def test_edit_course(
) )
r = app.lambda_handler( r = app.lambda_handler(
http_api_proxy( http_api_proxy(
raw_path='/courses/2a8963fc-4694-4fe2-953a-316d1b10f1f5', raw_path=f'/courses/{course_id}',
method=HTTPMethod.POST, method=HTTPMethod.PUT,
headers={ headers={
'Content-Type': m.content_type, 'Content-Type': m.content_type,
}, },
@@ -49,3 +53,10 @@ def test_edit_course(
), ),
lambda_context, lambda_context,
) )
assert r['statusCode'] == HTTPStatus.NO_CONTENT
r = dynamodb_persistence_layer.get_item(
key={'id': course_id, 'sk': '0'},
)
print(r)

View File

@@ -9,7 +9,7 @@ routes = [
mode = "smart" mode = "smart"
[vars] [vars]
ISSUER_URL = "https://58tkjsb308.execute-api.sa-east-1.amazonaws.com" ISSUER_URL = "https://duiolq49qn25e.cloudfront.net"
[observability.logs] [observability.logs]
enabled = true enabled = true

View File

@@ -100,3 +100,35 @@ Resources:
Path: /userinfo Path: /userinfo
Method: GET Method: GET
ApiId: !Ref HttpApi ApiId: !Ref HttpApi
OIDCDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
Origins:
- Id: OidcApiOrigin
DomainName: !Sub "${HttpApi}.execute-api.${AWS::Region}.amazonaws.com"
CustomOriginConfig:
OriginProtocolPolicy: https-only
DefaultCacheBehavior:
TargetOriginId: OidcApiOrigin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods: [GET, HEAD, OPTIONS, PUT, PATCH, POST, DELETE]
CachedMethods: [GET, HEAD, OPTIONS]
ForwardedValues:
QueryString: true
DefaultTTL: 0
MinTTL: 0
MaxTTL: 0
CacheBehaviors:
- PathPattern: "/.well-known/*"
TargetOriginId: OidcApiOrigin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods: [GET, HEAD, OPTIONS]
CachedMethods: [GET, HEAD, OPTIONS]
ForwardedValues:
QueryString: false
DefaultTTL: 3600 # 1 hora
MinTTL: 300 # 5 min
MaxTTL: 86400 # 1 dia