Files
saladeaula.digital/api.saladeaula.digital/app/routes/users/__init__.py
2025-12-03 01:24:52 -03:00

122 lines
3.1 KiB
Python

from http import HTTPStatus
from typing import Annotated
from aws_lambda_powertools.event_handler.api_gateway import Router
from aws_lambda_powertools.event_handler.exceptions import (
NotFoundError,
ServiceError,
)
from aws_lambda_powertools.event_handler.openapi.params import Body
from layercake.dateutils import now, ttl
from layercake.dynamodb import (
DynamoDBPersistenceLayer,
KeyPair,
SortKey,
TransactKey,
)
from layercake.extra_types import CpfStr, NameStr
from api_gateway import JSONResponse
from boto3clients import dynamodb_client
from config import USER_TABLE
from .emails import router as emails
from .orgs import router as orgs
from .password import router as password
__all__ = ['emails', 'orgs', 'password']
router = Router()
dyn = DynamoDBPersistenceLayer(USER_TABLE, dynamodb_client)
class UserNotFoundError(NotFoundError): ...
class CPFConflictError(ServiceError):
def __init__(self, msg: str | dict):
super().__init__(HTTPStatus.CONFLICT, msg)
class RateLimitExceededError(ServiceError):
def __init__(self, msg: str | dict):
super().__init__(HTTPStatus.TOO_MANY_REQUESTS, msg)
@router.get('/<user_id>')
def get_user(user_id: str):
user = dyn.collection.get_items(
TransactKey(user_id)
+ SortKey('0')
+ SortKey(
sk='RATE_LIMIT_EXCEEDED',
rename_key='rate_limit_exceeded',
)
+ SortKey(
sk='CREATED_BY',
rename_key='created_by',
),
)
if not user:
raise UserNotFoundError('User not found')
return user
@router.patch('/<user_id>')
def update(
user_id: str,
name: Annotated[NameStr, Body(embed=True)],
new_cpf: Annotated[CpfStr, Body(embed=True, alias='cpf')],
):
now_ = now()
old_cpf = dyn.collection.get_item(
KeyPair(
pk=user_id,
sk=SortKey('0', path_spec='cpf'),
),
)
with dyn.transact_writer() as transact:
transact.put(
item={
'id': user_id,
'sk': 'RATE_LIMIT_EXCEEDED',
'ttl': ttl(start_dt=now_, hours=24),
'created_at': now_,
},
cond_expr='attribute_not_exists(sk)',
exc_cls=RateLimitExceededError,
)
transact.update(
key=KeyPair(user_id, '0'),
update_expr='SET #name = :name, cpf = :cpf, updated_at = :now',
expr_attr_names={
'#name': 'name',
},
expr_attr_values={
':name': name,
':cpf': new_cpf,
':now': now_,
},
cond_expr='attribute_exists(sk)',
)
if old_cpf != new_cpf:
transact.put(
item={
'id': 'cpf',
'cpf': new_cpf,
'user_id': user_id,
'created_at': now_,
},
cond_expr='attribute_not_exists(sk)',
exc_cls=CPFConflictError,
)
if old_cpf:
transact.delete(key=KeyPair('cpf', old_cpf))
return JSONResponse(status_code=HTTPStatus.OK)