add typing

This commit is contained in:
2025-04-14 12:46:08 -03:00
parent e472826dcc
commit 558ea54929
7 changed files with 122 additions and 39 deletions

View File

@@ -2,11 +2,7 @@ import json
from http import HTTPStatus
from typing import Annotated
from aws_lambda_powertools.event_handler import content_types
from aws_lambda_powertools.event_handler.api_gateway import (
Response,
Router,
)
from aws_lambda_powertools.event_handler.api_gateway import Router
from aws_lambda_powertools.event_handler.exceptions import (
BadRequestError as PowertoolsBadRequestError,
)
@@ -24,12 +20,12 @@ from pydantic import UUID4, BaseModel, EmailStr, StringConstraints
import cognito
import elastic
import middlewares
from api_gateway import JSONResponse
from boto3clients import dynamodb_client, idp_client
from middlewares import AuditLogMiddleware
from models import User
from settings import ELASTIC_CONN, USER_POOOL_ID, USER_TABLE
from user import add_email, del_email
from user import add_email, del_email, set_email_as_primary
class BadRequestError(MissingError, PowertoolsBadRequestError): ...
@@ -63,7 +59,7 @@ def get_users():
middlewares=[AuditLogMiddleware('USER_ADD', user_collect)],
)
def post_user(payload: User):
return Response(status_code=HTTPStatus.CREATED)
return JSONResponse(status_code=HTTPStatus.CREATED)
class Password(BaseModel):
@@ -87,13 +83,11 @@ def password(id: str, payload: Password):
user_pool_id=USER_POOOL_ID,
idp_client=idp_client,
)
return Response(
return JSONResponse(
body={
'id': id,
'cognito_sub': payload.cognito_sub,
},
content_type=content_types.APPLICATION_JSON,
status_code=HTTPStatus.OK,
)
@@ -137,14 +131,46 @@ class Email(BaseModel):
middlewares=[AuditLogMiddleware('EMAIL_ADD', user_collect, ('email',))],
)
def post_email(id: str, payload: Email):
assert add_email(id, payload.email, persistence_layer=user_layer)
return Response(
add_email(id, payload.email, persistence_layer=user_layer)
return JSONResponse(
body=payload,
content_type=content_types.APPLICATION_JSON,
status_code=HTTPStatus.CREATED,
)
class EmailAsPrimary(BaseModel):
new_email: EmailStr
old_email: EmailStr
email_verified: bool = False
@router.patch(
'/<id>/emails',
compress=True,
tags=['User'],
summary='Add user email as primary',
middlewares=[
AuditLogMiddleware(
'EMAIL_CHANGE',
user_collect,
(
'new_email',
'old_email',
),
)
],
)
def patch_email(id: str, payload: EmailAsPrimary):
set_email_as_primary(
id,
payload.new_email,
payload.old_email,
email_verified=payload.email_verified,
persistence_layer=user_layer,
)
return JSONResponse(body=payload, status_code=HTTPStatus.OK)
@router.delete(
'/<id>/emails',
compress=True,

View File

@@ -23,7 +23,7 @@ Globals:
Architectures:
- x86_64
Layers:
- !Sub arn:aws:lambda:sa-east-1:336641857101:layer:layercake:46
- !Sub arn:aws:lambda:sa-east-1:336641857101:layer:layercake:47
Environment:
Variables:
TZ: America/Sao_Paulo

View File

@@ -148,6 +148,36 @@ def test_post_email(
}
def test_patch_email(
mock_app,
dynamodb_client,
dynamodb_seeds,
dynamodb_persistence_layer: DynamoDBPersistenceLayer,
http_api_proxy: HttpApiProxy,
lambda_context: LambdaContext,
):
r = mock_app.lambda_handler(
http_api_proxy(
raw_path='/users/5OxmMjL-ujoR5IMGegQz/emails',
method=HTTPMethod.PATCH,
body={
'old_email': 'sergio@somosbeta.com.br',
'new_email': 'osergiosiqueira@gmail.com',
},
),
lambda_context,
)
assert r['statusCode'] == HTTPStatus.OK
collect = DynamoDBCollection(dynamodb_persistence_layer)
user = collect.get_item(KeyPair('5OxmMjL-ujoR5IMGegQz', '0'))
print(user)
# assert user['emails'] == {
# 'sergio@somosbeta.com.br',
# }
def test_delete_email(
mock_app,
dynamodb_client,

View File

@@ -83,3 +83,49 @@ def del_email(
return persistence_layer.transact_write_items(transact)
except ClientError:
raise BadRequestError('Cannot remove the primary email.')
def set_email_as_primary(
id: str,
new_email: str,
old_email: str,
/,
*,
email_verified: bool = False,
persistence_layer: DynamoDBPersistenceLayer,
):
now_ = now()
expr = 'SET email_primary = :email_primary, update_date = :update_date'
transact = TransactItems(persistence_layer.table_name)
transact.update(
key=KeyPair(id, ComposeKey(old_email, 'emails')),
update_expr=expr,
expr_attr_values={
':email_primary': False,
':update_date': now_,
},
)
# Set the new email as primary
transact.update(
key=KeyPair(id, ComposeKey(new_email, 'emails')),
update_expr=expr,
expr_attr_values={
':email_primary': True,
':update_date': now_,
},
)
transact.update(
key=KeyPair(id, '0'),
update_expr=(
'SET email = :email, email_verified = :email_verified, '
'update_date = :update_date'
),
expr_attr_values={
':email': new_email,
':email_verified': email_verified,
':update_date': now_,
},
)
return persistence_layer.transact_write_items(transact)

25
http-api/uv.lock generated
View File

@@ -521,7 +521,7 @@ wheels = [
[[package]]
name = "layercake"
version = "0.2.9"
version = "0.2.10"
source = { directory = "../layercake" }
dependencies = [
{ name = "arnparse" },
@@ -538,7 +538,6 @@ dependencies = [
{ name = "pydantic-extra-types" },
{ name = "pytz" },
{ name = "requests" },
{ name = "uuid-utils" },
{ name = "weasyprint" },
]
@@ -558,12 +557,12 @@ requires-dist = [
{ name = "pydantic-extra-types", specifier = ">=2.10.3" },
{ name = "pytz", specifier = ">=2025.1" },
{ name = "requests", specifier = ">=2.32.3" },
{ name = "uuid-utils", specifier = ">=0.10.0" },
{ name = "weasyprint", specifier = ">=65.0" },
]
[package.metadata.requires-dev]
dev = [
{ name = "boto3-stubs", extras = ["essential"], specifier = ">=1.37.33" },
{ name = "jsonlines", specifier = ">=4.0.0" },
{ name = "mkdocstrings", extras = ["python"], specifier = ">=0.29.0" },
{ name = "pytest", specifier = ">=8.3.5" },
@@ -940,26 +939,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 },
]
[[package]]
name = "uuid-utils"
version = "0.10.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/66/0a/cbdb2eb4845dafeb632d02a18f47b02f87f2ce4f25266f5e3c017976ce89/uuid_utils-0.10.0.tar.gz", hash = "sha256:5db0e1890e8f008657ffe6ded4d9459af724ab114cfe82af1557c87545301539", size = 18828 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/44/54/9d22fa16b19e5d1676eba510f08a9c458d96e2a62ff2c8ebad64251afb18/uuid_utils-0.10.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8d5a4508feefec62456cd6a41bcdde458d56827d908f226803b886d22a3d5e63", size = 573006 },
{ url = "https://files.pythonhosted.org/packages/08/8e/f895c6e52aa603e521fbc13b8626ba5dd99b6e2f5a55aa96ba5b232f4c53/uuid_utils-0.10.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:dbefc2b9113f9dfe56bdae58301a2b3c53792221410d422826f3d1e3e6555fe7", size = 292543 },
{ url = "https://files.pythonhosted.org/packages/b6/58/cc4834f377a5e97d6e184408ad96d13042308de56643b6e24afe1f6f34df/uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffc49c33edf87d1ec8112a9b43e4cf55326877716f929c165a2cc307d31c73d5", size = 323340 },
{ url = "https://files.pythonhosted.org/packages/37/e3/6aeddf148f6a7dd7759621b000e8c85382ec83f52ae79b60842d1dc3ab6b/uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0636b6208f69d5a4e629707ad2a89a04dfa8d1023e1999181f6830646ca048a1", size = 329653 },
{ url = "https://files.pythonhosted.org/packages/0c/00/dd6c2164ace70b7b1671d9129267df331481d7d1e5f9c5e6a564f07953f6/uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bc06452856b724df9dedfc161c3582199547da54aeb81915ec2ed54f92d19b0", size = 365471 },
{ url = "https://files.pythonhosted.org/packages/b4/e7/0ab8080fcae5462a7b5e555c1cef3d63457baffb97a59b9bc7b005a3ecb1/uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:263b2589111c61decdd74a762e8f850c9e4386fb78d2cf7cb4dfc537054cda1b", size = 325844 },
{ url = "https://files.pythonhosted.org/packages/73/39/52d94e9ef75b03f44b39ffc6ac3167e93e74ef4d010a93d25589d9f48540/uuid_utils-0.10.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a558db48b7096de6b4d2d2210d82bba8586a6d55f99106b03bb7d01dc5c5bcd6", size = 344389 },
{ url = "https://files.pythonhosted.org/packages/7c/29/4824566f62666238290d99c62a58e4ab2a8b9cf2eccf94cebd9b3359131e/uuid_utils-0.10.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:807465067f3c892514230326ac71a79b28a8dfe2c88ecd2d5675fc844f3c76b5", size = 510078 },
{ url = "https://files.pythonhosted.org/packages/5e/8f/bbcc7130d652462c685f0d3bd26bb214b754215b476340885a4cb50fb89a/uuid_utils-0.10.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:57423d4a2b9d7b916de6dbd75ba85465a28f9578a89a97f7d3e098d9aa4e5d4a", size = 515937 },
{ url = "https://files.pythonhosted.org/packages/23/f8/34e0c00f5f188604d336713e6a020fcf53b10998e8ab24735a39ab076740/uuid_utils-0.10.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:76d8d660f18ff6b767e319b1b5f927350cd92eafa4831d7ef5b57fdd1d91f974", size = 494111 },
{ url = "https://files.pythonhosted.org/packages/1a/52/b7f0066cc90a7a9c28d54061ed195cd617fde822e5d6ac3ccc88509c3c44/uuid_utils-0.10.0-cp39-abi3-win32.whl", hash = "sha256:6c11a71489338837db0b902b75e1ba7618d5d29f05fde4f68b3f909177dbc226", size = 173520 },
{ url = "https://files.pythonhosted.org/packages/8b/15/f04f58094674d333974243fb45d2c740cf4b79186fb707168e57943c84a3/uuid_utils-0.10.0-cp39-abi3-win_amd64.whl", hash = "sha256:11c55ae64f6c0a7a0c741deae8ca2a4eaa11e9c09dbb7bec2099635696034cf7", size = 182965 },
]
[[package]]
name = "wcwidth"
version = "0.2.13"