add user if exists on konviva
This commit is contained in:
@@ -53,7 +53,7 @@ app = APIGatewayHttpResolver(
|
|||||||
app.use(middlewares=[AuthenticationMiddleware()])
|
app.use(middlewares=[AuthenticationMiddleware()])
|
||||||
app.include_router(courses.router, prefix='/courses')
|
app.include_router(courses.router, prefix='/courses')
|
||||||
app.include_router(enrollments.router, prefix='/enrollments')
|
app.include_router(enrollments.router, prefix='/enrollments')
|
||||||
app.include_router(enrollments.vacancies, prefix='/enrollments')
|
app.include_router(enrollments.slots, prefix='/enrollments')
|
||||||
app.include_router(enrollments.enroll, prefix='/enrollments')
|
app.include_router(enrollments.enroll, prefix='/enrollments')
|
||||||
app.include_router(enrollments.cancel, prefix='/enrollments')
|
app.include_router(enrollments.cancel, prefix='/enrollments')
|
||||||
app.include_router(orders.router, prefix='/orders')
|
app.include_router(orders.router, prefix='/orders')
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class KonvivaError(BadRequestError):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass(frozen=True)
|
||||||
class KonvivaToken:
|
class KonvivaToken:
|
||||||
login: str
|
login: str
|
||||||
token: str
|
token: str
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ from config import ELASTIC_CONN, ENROLLMENT_TABLE, USER_TABLE
|
|||||||
|
|
||||||
from .cancel import router as cancel
|
from .cancel import router as cancel
|
||||||
from .enroll import router as enroll
|
from .enroll import router as enroll
|
||||||
from .vacancies import router as vacancies
|
from .slots import router as slots
|
||||||
|
|
||||||
__all__ = ['vacancies', 'cancel', 'enroll']
|
__all__ = ['slots', 'cancel', 'enroll']
|
||||||
|
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
|
|||||||
@@ -1,28 +1,19 @@
|
|||||||
from aws_lambda_powertools.event_handler.api_gateway import Router
|
from aws_lambda_powertools.event_handler.api_gateway import Router
|
||||||
from elasticsearch import Elasticsearch
|
|
||||||
from layercake.dynamodb import (
|
from layercake.dynamodb import (
|
||||||
DynamoDBCollection,
|
|
||||||
DynamoDBPersistenceLayer,
|
DynamoDBPersistenceLayer,
|
||||||
KeyPair,
|
KeyPair,
|
||||||
)
|
)
|
||||||
from pydantic import UUID4, BaseModel
|
from pydantic import UUID4, BaseModel
|
||||||
|
|
||||||
from boto3clients import dynamodb_client
|
from boto3clients import dynamodb_client
|
||||||
from config import ELASTIC_CONN, ENROLLMENT_TABLE, USER_TABLE
|
from config import ENROLLMENT_TABLE, USER_TABLE
|
||||||
from middlewares.audit_log_middleware import AuditLogMiddleware
|
from middlewares.audit_log_middleware import AuditLogMiddleware
|
||||||
from middlewares.authentication_middleware import User
|
from middlewares.authentication_middleware import User
|
||||||
from rules.enrollment import set_status_as_canceled
|
from rules.enrollment import set_status_as_canceled
|
||||||
|
|
||||||
from .vacancies import router as vacancies
|
|
||||||
|
|
||||||
__all__ = ['vacancies']
|
|
||||||
|
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
elastic_client = Elasticsearch(**ELASTIC_CONN)
|
|
||||||
enrollment_layer = DynamoDBPersistenceLayer(ENROLLMENT_TABLE, dynamodb_client)
|
enrollment_layer = DynamoDBPersistenceLayer(ENROLLMENT_TABLE, dynamodb_client)
|
||||||
user_layer = DynamoDBPersistenceLayer(USER_TABLE, dynamodb_client)
|
user_layer = DynamoDBPersistenceLayer(USER_TABLE, dynamodb_client)
|
||||||
user_collect = DynamoDBCollection(user_layer)
|
|
||||||
|
|
||||||
|
|
||||||
class Cancel(BaseModel):
|
class Cancel(BaseModel):
|
||||||
@@ -37,7 +28,11 @@ class Cancel(BaseModel):
|
|||||||
compress=True,
|
compress=True,
|
||||||
tags=['Enrollment'],
|
tags=['Enrollment'],
|
||||||
middlewares=[
|
middlewares=[
|
||||||
AuditLogMiddleware('ENROLLMENT_CANCEL', user_collect, ('id', 'course'))
|
AuditLogMiddleware(
|
||||||
|
'ENROLLMENT_CANCEL',
|
||||||
|
collection=user_layer.collection,
|
||||||
|
audit_attrs=('id', 'course'),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def cancel(id: str, payload: Cancel):
|
def cancel(id: str, payload: Cancel):
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from config import (
|
|||||||
)
|
)
|
||||||
from middlewares import Tenant, TenantMiddleware
|
from middlewares import Tenant, TenantMiddleware
|
||||||
from models import Course, Enrollment, User
|
from models import Course, Enrollment, User
|
||||||
from rules.enrollment import DeduplicationWindow, Vacancy, enroll
|
from rules.enrollment import DeduplicationWindow, Slot, enroll
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
|
|
||||||
@@ -32,16 +32,16 @@ processor = BatchProcessor()
|
|||||||
class Item(BaseModel):
|
class Item(BaseModel):
|
||||||
user: User
|
user: User
|
||||||
course: Course
|
course: Course
|
||||||
vacancy: Vacancy | None = None
|
slot: Slot | None = None
|
||||||
deduplication_window: DeduplicationWindow | None = None
|
deduplication_window: DeduplicationWindow | None = None
|
||||||
schedule_date: datetime | None = None
|
schedule_date: datetime | None = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self) -> str:
|
def id(self) -> str:
|
||||||
if not self.vacancy:
|
if not self.slot:
|
||||||
return str(uuid.uuid4())
|
return str(uuid.uuid4())
|
||||||
|
|
||||||
_, idx = self.vacancy.sk.split('#')
|
_, idx = self.slot.sk.split('#')
|
||||||
return idx
|
return idx
|
||||||
|
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ def handler(record: Item, context: dict):
|
|||||||
'name': tenant.name,
|
'name': tenant.name,
|
||||||
},
|
},
|
||||||
deduplication_window=record.deduplication_window,
|
deduplication_window=record.deduplication_window,
|
||||||
vacancy=record.vacancy,
|
slot=record.slot,
|
||||||
persistence_layer=enrollment_layer,
|
persistence_layer=enrollment_layer,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
from aws_lambda_powertools.event_handler.api_gateway import Router
|
|
||||||
from layercake.dynamodb import (
|
|
||||||
ComposeKey,
|
|
||||||
DynamoDBCollection,
|
|
||||||
DynamoDBPersistenceLayer,
|
|
||||||
PartitionKey,
|
|
||||||
)
|
|
||||||
|
|
||||||
from boto3clients import dynamodb_client
|
|
||||||
from config import (
|
|
||||||
ENROLLMENT_TABLE,
|
|
||||||
USER_TABLE,
|
|
||||||
)
|
|
||||||
from middlewares import Tenant, TenantMiddleware
|
|
||||||
|
|
||||||
router = Router()
|
|
||||||
|
|
||||||
enrollment_layer = DynamoDBPersistenceLayer(ENROLLMENT_TABLE, dynamodb_client)
|
|
||||||
user_layer = DynamoDBPersistenceLayer(USER_TABLE, dynamodb_client)
|
|
||||||
user_collect = DynamoDBCollection(user_layer)
|
|
||||||
enrollment_collect = DynamoDBCollection(enrollment_layer)
|
|
||||||
|
|
||||||
|
|
||||||
@router.get(
|
|
||||||
'/vacancies',
|
|
||||||
compress=True,
|
|
||||||
tags=['Enrollment'],
|
|
||||||
middlewares=[
|
|
||||||
TenantMiddleware(user_collect),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def get_vacancies():
|
|
||||||
tenant: Tenant = router.context['tenant']
|
|
||||||
|
|
||||||
return enrollment_collect.query(
|
|
||||||
PartitionKey(
|
|
||||||
ComposeKey(str(tenant.id), prefix='vacancies'),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
@@ -28,7 +28,7 @@ class LinkedEntity(str):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class Vacancy:
|
class Slot:
|
||||||
id: str
|
id: str
|
||||||
sk: str
|
sk: str
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ def enroll(
|
|||||||
enrollment: Enrollment,
|
enrollment: Enrollment,
|
||||||
*,
|
*,
|
||||||
tenant: Tenant,
|
tenant: Tenant,
|
||||||
vacancy: Vacancy | None = None,
|
slot: Slot | None = None,
|
||||||
author: Author | None = None,
|
author: Author | None = None,
|
||||||
linked_entities: frozenset[LinkedEntity] = frozenset(),
|
linked_entities: frozenset[LinkedEntity] = frozenset(),
|
||||||
deduplication_window: DeduplicationWindow | None = None,
|
deduplication_window: DeduplicationWindow | None = None,
|
||||||
@@ -83,14 +83,14 @@ def enroll(
|
|||||||
lock_hash = md5_hash('%s%s' % (user.id, course.id))
|
lock_hash = md5_hash('%s%s' % (user.id, course.id))
|
||||||
|
|
||||||
with persistence_layer.transact_writer() as transact:
|
with persistence_layer.transact_writer() as transact:
|
||||||
if vacancy:
|
if slot:
|
||||||
linked_entities = frozenset({vacancy.order_id}) | linked_entities
|
linked_entities = frozenset({slot.order_id}) | linked_entities
|
||||||
|
|
||||||
transact.put(
|
transact.put(
|
||||||
item={
|
item={
|
||||||
'sk': '0',
|
'sk': '0',
|
||||||
'create_date': now_,
|
'created_at': now_,
|
||||||
'tenant': tenant_id,
|
'tenant_id': tenant_id,
|
||||||
**enrollment.model_dump(),
|
**enrollment.model_dump(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -157,14 +157,14 @@ def enroll(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if vacancy:
|
if slot:
|
||||||
transact.put(
|
transact.put(
|
||||||
item={
|
item={
|
||||||
'id': enrollment.id,
|
'id': enrollment.id,
|
||||||
# Post-migration: uncomment the following line
|
# Post-migration: uncomment the following line
|
||||||
# 'sk': 'metadata#parent_slot',
|
# 'sk': 'metadata#parent_slot',
|
||||||
'sk': 'parent_vacancy',
|
'sk': 'parent_vacancy',
|
||||||
'vacancy': asdict(vacancy),
|
'vacancy': asdict(slot),
|
||||||
'created_at': now_,
|
'created_at': now_,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -174,7 +174,7 @@ def enroll(
|
|||||||
super().__init__('Slot does not exist')
|
super().__init__('Slot does not exist')
|
||||||
|
|
||||||
transact.delete(
|
transact.delete(
|
||||||
key=KeyPair(vacancy.id, vacancy.sk),
|
key=KeyPair(slot.id, slot.sk),
|
||||||
cond_expr='attribute_exists(sk)',
|
cond_expr='attribute_exists(sk)',
|
||||||
exc_cls=SlotDoesNotExistError,
|
exc_cls=SlotDoesNotExistError,
|
||||||
)
|
)
|
||||||
|
|||||||
13
konviva-events/app/boto3clients.py
Normal file
13
konviva-events/app/boto3clients.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
import boto3
|
||||||
|
|
||||||
|
|
||||||
|
def get_dynamodb_client():
|
||||||
|
if os.getenv('AWS_LAMBDA_FUNCTION_NAME'):
|
||||||
|
return boto3.client('dynamodb')
|
||||||
|
|
||||||
|
return boto3.client('dynamodb', endpoint_url='http://127.0.0.1:8000')
|
||||||
|
|
||||||
|
|
||||||
|
dynamodb_client = get_dynamodb_client()
|
||||||
6
konviva-events/app/config.py
Normal file
6
konviva-events/app/config.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
USER_TABLE: str = os.getenv('USER_TABLE') # type: ignore
|
||||||
|
|
||||||
|
KONVIVA_API_URL: str = os.getenv('KONVIVA_API_URL') # type: ignore
|
||||||
|
KONVIVA_SECRET_KEY: str = os.getenv('KONVIVA_SECRET_KEY') # type:ignore
|
||||||
70
konviva-events/app/events/create_user.py
Normal file
70
konviva-events/app/events/create_user.py
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
from aws_lambda_powertools import Logger
|
||||||
|
from aws_lambda_powertools.utilities.data_classes import (
|
||||||
|
EventBridgeEvent,
|
||||||
|
event_source,
|
||||||
|
)
|
||||||
|
from aws_lambda_powertools.utilities.typing import LambdaContext
|
||||||
|
from glom import glom
|
||||||
|
from layercake.dateutils import now
|
||||||
|
from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair
|
||||||
|
|
||||||
|
import konviva
|
||||||
|
from boto3clients import dynamodb_client
|
||||||
|
from config import USER_TABLE
|
||||||
|
|
||||||
|
logger = Logger(__name__)
|
||||||
|
user_layer = DynamoDBPersistenceLayer(USER_TABLE, dynamodb_client)
|
||||||
|
|
||||||
|
|
||||||
|
class UserNotFoundError(Exception): ...
|
||||||
|
|
||||||
|
|
||||||
|
@event_source(data_class=EventBridgeEvent)
|
||||||
|
@logger.inject_lambda_context
|
||||||
|
def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
|
||||||
|
new_image = event.detail['new_image']
|
||||||
|
now_ = now()
|
||||||
|
|
||||||
|
try:
|
||||||
|
user_id = konviva.create_user(
|
||||||
|
id=new_image['id'],
|
||||||
|
name=new_image['name'],
|
||||||
|
email=new_image['email'],
|
||||||
|
cpf=new_image.get('cpf', None),
|
||||||
|
)
|
||||||
|
except konviva.EmailAlreadyExists:
|
||||||
|
logger.info(
|
||||||
|
'Email already exists, retrieving existing user',
|
||||||
|
email=new_image['email'],
|
||||||
|
)
|
||||||
|
|
||||||
|
r = konviva.get_users_by_email(new_image['email'])
|
||||||
|
user_id = glom(r, '0.IDUsuario')
|
||||||
|
|
||||||
|
if not r:
|
||||||
|
raise UserNotFoundError()
|
||||||
|
except Exception:
|
||||||
|
raise
|
||||||
|
|
||||||
|
with user_layer.transact_writer() as transact:
|
||||||
|
transact.update(
|
||||||
|
key=KeyPair(new_image['id'], '0'),
|
||||||
|
update_expr='SET metadata__konviva_user_id = :user_id, \
|
||||||
|
updated_at = :updated_at',
|
||||||
|
expr_attr_values={
|
||||||
|
':user_id': user_id,
|
||||||
|
':updated_at': now_,
|
||||||
|
},
|
||||||
|
cond_expr='attribute_exists(sk)',
|
||||||
|
)
|
||||||
|
# Post-migration: remove the following line
|
||||||
|
transact.put(
|
||||||
|
item={
|
||||||
|
'id': new_image['id'],
|
||||||
|
'sk': 'konviva',
|
||||||
|
'konvivaId': user_id,
|
||||||
|
'created_at': now_,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
99
konviva-events/app/konviva.py
Normal file
99
konviva-events/app/konviva.py
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
import random
|
||||||
|
import string
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from urllib.parse import quote_plus, urlparse
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from aws_lambda_powertools.event_handler.exceptions import BadRequestError
|
||||||
|
from glom import glom
|
||||||
|
|
||||||
|
from config import KONVIVA_API_URL, KONVIVA_SECRET_KEY
|
||||||
|
|
||||||
|
ALU = 2
|
||||||
|
GES = 3
|
||||||
|
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'Authorization': f'KONVIVA {KONVIVA_SECRET_KEY}',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def random_str(maxlen: int = 10) -> str:
|
||||||
|
"""Returns a random string of letters."""
|
||||||
|
return ''.join(random.choice(string.ascii_letters) for _ in range(maxlen))
|
||||||
|
|
||||||
|
|
||||||
|
class KonvivaError(BadRequestError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class EmailAlreadyExists(KonvivaError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class User:
|
||||||
|
IDUsuario: int
|
||||||
|
Identificador: str
|
||||||
|
NomeUsuario: str
|
||||||
|
Email: str
|
||||||
|
CPF: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
def create_user(
|
||||||
|
id: str,
|
||||||
|
name: str,
|
||||||
|
email: str,
|
||||||
|
cpf: str | None,
|
||||||
|
) -> dict:
|
||||||
|
url = urlparse(KONVIVA_API_URL)._replace(
|
||||||
|
path='/action/api/integrarUsuario',
|
||||||
|
query='sendMail=false',
|
||||||
|
)
|
||||||
|
|
||||||
|
r = requests.post(
|
||||||
|
url=url.geturl(),
|
||||||
|
headers=headers,
|
||||||
|
json={
|
||||||
|
'Identificador': id,
|
||||||
|
'NomeUsuario': name,
|
||||||
|
'Login': email,
|
||||||
|
'Email': email,
|
||||||
|
'CPF': cpf,
|
||||||
|
'Senha': random_str(30),
|
||||||
|
'Situacao': 'ATIVO',
|
||||||
|
'UnidadesPerfil': [
|
||||||
|
{
|
||||||
|
'IDPerfil': ALU,
|
||||||
|
'CODPerfil': 'ALU',
|
||||||
|
'CODUnidade': '1380e6d0-fee8-4cb9-9bf0-a087e703b1a4',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
r.raise_for_status()
|
||||||
|
|
||||||
|
# Because Konviva does not return the proper HTTP status code
|
||||||
|
if err := glom(r.json(), 'errors', default=None):
|
||||||
|
err = err[0] if isinstance(err, list) else err
|
||||||
|
raise EmailAlreadyExists(err)
|
||||||
|
|
||||||
|
return r.json().get('IDUsuario')
|
||||||
|
|
||||||
|
|
||||||
|
def get_users_by_email(email: str) -> list[dict]:
|
||||||
|
url = urlparse(KONVIVA_API_URL)._replace(
|
||||||
|
path='/action/api/getUsuariosByQuery',
|
||||||
|
query=f'q=Email=={quote_plus(email)}',
|
||||||
|
)
|
||||||
|
r = requests.get(
|
||||||
|
url=url.geturl(),
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
r.raise_for_status()
|
||||||
|
|
||||||
|
if glom(r.json(), '0.errors', default=None):
|
||||||
|
return []
|
||||||
|
|
||||||
|
return r.json()
|
||||||
6
konviva-events/config.py
Normal file
6
konviva-events/config.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
USER_TABLE: str = os.getenv('USER_TABLE') # type: ignore
|
||||||
|
|
||||||
|
KONVIVA_API_URL: str = os.getenv('KONVIVA_API_URL') # type: ignore
|
||||||
|
KONVIVA_SECRET_KEY: str = os.getenv('KONVIVA_SECRET_KEY') # type:ignore
|
||||||
33
konviva-events/pyproject.toml
Normal file
33
konviva-events/pyproject.toml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
[project]
|
||||||
|
name = "konviva-events"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = ""
|
||||||
|
readme = ""
|
||||||
|
requires-python = ">=3.13"
|
||||||
|
dependencies = ["layercake"]
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
|
dev = [
|
||||||
|
"jsonlines>=4.0.0",
|
||||||
|
"pytest>=8.3.4",
|
||||||
|
"pytest-cov>=6.0.0",
|
||||||
|
"ruff>=0.9.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.pytest.ini_options]
|
||||||
|
pythonpath = ["app/"]
|
||||||
|
addopts = "--cov --cov-report html -v"
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
target-version = "py311"
|
||||||
|
src = ["app"]
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
quote-style = "single"
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
select = ["E", "F", "I"]
|
||||||
|
|
||||||
|
|
||||||
|
[tool.uv.sources]
|
||||||
|
layercake = { path = "../layercake" }
|
||||||
3
konviva-events/pyrightconfig.json
Normal file
3
konviva-events/pyrightconfig.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"extraPaths": ["app/"]
|
||||||
|
}
|
||||||
9
konviva-events/samconfig.toml
Normal file
9
konviva-events/samconfig.toml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
version = 0.1
|
||||||
|
[default.deploy.parameters]
|
||||||
|
stack_name = "saladeaula-konviva-events"
|
||||||
|
resolve_s3 = true
|
||||||
|
s3_prefix = "konviva-events"
|
||||||
|
region = "sa-east-1"
|
||||||
|
confirm_changeset = false
|
||||||
|
capabilities = "CAPABILITY_IAM"
|
||||||
|
image_repositories = []
|
||||||
57
konviva-events/template.yaml
Normal file
57
konviva-events/template.yaml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
AWSTemplateFormatVersion: 2010-09-09
|
||||||
|
Transform: AWS::Serverless-2016-10-31
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
UserTable:
|
||||||
|
Type: String
|
||||||
|
Default: betaeducacao-prod-users_d2o3r5gmm4it7j
|
||||||
|
|
||||||
|
Globals:
|
||||||
|
Function:
|
||||||
|
CodeUri: app/
|
||||||
|
Runtime: python3.13
|
||||||
|
Tracing: Active
|
||||||
|
Architectures:
|
||||||
|
- x86_64
|
||||||
|
Layers:
|
||||||
|
- !Sub arn:aws:lambda:sa-east-1:336641857101:layer:layercake:79
|
||||||
|
Environment:
|
||||||
|
Variables:
|
||||||
|
TZ: America/Sao_Paulo
|
||||||
|
LOG_LEVEL: DEBUG
|
||||||
|
DYNAMODB_PARTITION_KEY: id
|
||||||
|
POWERTOOLS_LOGGER_SAMPLE_RATE: 0.1
|
||||||
|
POWERTOOLS_LOGGER_LOG_EVENT: true
|
||||||
|
USER_TABLE: !Ref UserTable
|
||||||
|
KONVIVA_API_URL: https://lms.saladeaula.digital
|
||||||
|
KONVIVA_SECRET_KEY: "{{resolve:ssm:/betaeducacao/konviva/secret_key/str}}"
|
||||||
|
|
||||||
|
Resources:
|
||||||
|
EventLog:
|
||||||
|
Type: AWS::Logs::LogGroup
|
||||||
|
Properties:
|
||||||
|
RetentionInDays: 90
|
||||||
|
|
||||||
|
EventCreateUserFunction:
|
||||||
|
Type: AWS::Serverless::Function
|
||||||
|
Properties:
|
||||||
|
Handler: events.create_user.lambda_handler
|
||||||
|
LoggingConfig:
|
||||||
|
LogGroup: !Ref EventLog
|
||||||
|
Policies:
|
||||||
|
- DynamoDBWritePolicy:
|
||||||
|
TableName: !Ref UserTable
|
||||||
|
Events:
|
||||||
|
DynamoDBEvent:
|
||||||
|
Type: EventBridgeRule
|
||||||
|
Properties:
|
||||||
|
Pattern:
|
||||||
|
resources: [!Ref UserTable]
|
||||||
|
detail-type: [INSERT]
|
||||||
|
detail:
|
||||||
|
new_image:
|
||||||
|
sk: ["0"]
|
||||||
|
cnpj:
|
||||||
|
- exists: false
|
||||||
|
metadata__konviva_user_id:
|
||||||
|
- exists: false
|
||||||
0
konviva-events/tests/__init__.py
Normal file
0
konviva-events/tests/__init__.py
Normal file
63
konviva-events/tests/conftest.py
Normal file
63
konviva-events/tests/conftest.py
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import os
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
import jsonlines
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
PYTEST_TABLE_NAME = 'pytest'
|
||||||
|
PK = 'id'
|
||||||
|
SK = 'sk'
|
||||||
|
|
||||||
|
|
||||||
|
# https://docs.pytest.org/en/7.1.x/reference/reference.html#pytest.hookspec.pytest_configure
|
||||||
|
def pytest_configure():
|
||||||
|
os.environ['TZ'] = 'America/Sao_Paulo'
|
||||||
|
os.environ['DYNAMODB_PARTITION_KEY'] = PK
|
||||||
|
os.environ['DYNAMODB_SORT_KEY'] = SK
|
||||||
|
os.environ['USER_TABLE'] = PYTEST_TABLE_NAME
|
||||||
|
os.environ['KONVIVA_API_URL'] = 'https://lms.saladeaula.digital'
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class LambdaContext:
|
||||||
|
function_name: str = 'test'
|
||||||
|
memory_limit_in_mb: int = 128
|
||||||
|
invoked_function_arn: str = 'arn:aws:lambda:eu-west-1:809313241:function:test'
|
||||||
|
aws_request_id: str = '52fdfc07-2182-154f-163f-5f0f9a621d72'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def lambda_context() -> LambdaContext:
|
||||||
|
return LambdaContext()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def dynamodb_client():
|
||||||
|
from boto3clients import dynamodb_client as client
|
||||||
|
|
||||||
|
client.create_table(
|
||||||
|
AttributeDefinitions=[
|
||||||
|
{'AttributeName': PK, 'AttributeType': 'S'},
|
||||||
|
{'AttributeName': SK, 'AttributeType': 'S'},
|
||||||
|
],
|
||||||
|
TableName=PYTEST_TABLE_NAME,
|
||||||
|
KeySchema=[
|
||||||
|
{'AttributeName': PK, 'KeyType': 'HASH'},
|
||||||
|
{'AttributeName': SK, 'KeyType': 'RANGE'},
|
||||||
|
],
|
||||||
|
ProvisionedThroughput={
|
||||||
|
'ReadCapacityUnits': 123,
|
||||||
|
'WriteCapacityUnits': 123,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
yield client
|
||||||
|
|
||||||
|
client.delete_table(TableName=PYTEST_TABLE_NAME)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def dynamodb_seeds(dynamodb_client):
|
||||||
|
with jsonlines.open('tests/seeds.jsonl') as lines:
|
||||||
|
for line in lines:
|
||||||
|
dynamodb_client.put_item(TableName=PYTEST_TABLE_NAME, Item=line)
|
||||||
0
konviva-events/tests/events/__init__.py
Normal file
0
konviva-events/tests/events/__init__.py
Normal file
19
konviva-events/tests/events/test_create_user.py
Normal file
19
konviva-events/tests/events/test_create_user.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
from aws_lambda_powertools.utilities.typing import LambdaContext
|
||||||
|
|
||||||
|
import events.create_user as app
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_user(dynamodb_client, dynamodb_seeds, lambda_context: LambdaContext):
|
||||||
|
event = {
|
||||||
|
'detail': {
|
||||||
|
'new_image': {
|
||||||
|
'id': '123',
|
||||||
|
'sk': '0',
|
||||||
|
'name': 'Sérgio R Siqueira',
|
||||||
|
'email': 'sergio@somosbeta.com.br',
|
||||||
|
'cpf': '07879819908',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert app.lambda_handler(event, lambda_context) # type: ignore
|
||||||
1
konviva-events/tests/seeds.jsonl
Normal file
1
konviva-events/tests/seeds.jsonl
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"id": {"S": "123"}, "sk": {"S": "0"}}
|
||||||
23
konviva-events/tests/test_konviva.py
Normal file
23
konviva-events/tests/test_konviva.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
import konviva
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_user_email_exists():
|
||||||
|
with pytest.raises(konviva.KonvivaError):
|
||||||
|
konviva.create_user(
|
||||||
|
id='',
|
||||||
|
name='Sérgio R Siquira',
|
||||||
|
email='sergio@somosbeta.com.br',
|
||||||
|
cpf='0879819908',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_users_by_email():
|
||||||
|
r = konviva.get_users_by_email('sergio@somosbeta.com.br')
|
||||||
|
assert len(r) >= 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_users_by_email_notfound():
|
||||||
|
r = konviva.get_users_by_email('fake@fake.com')
|
||||||
|
assert r == []
|
||||||
1207
konviva-events/uv.lock
generated
Normal file
1207
konviva-events/uv.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user