This commit is contained in:
2025-03-27 11:54:19 -03:00
parent 8118dfd403
commit 76c2656dd1
15 changed files with 200 additions and 151 deletions

View File

@@ -8,9 +8,12 @@ start-api: build
sam local start-api sam local start-api
openapi: openapi:
uv run openapi.py && \ uv run -m cli.openapi && \
uv run python -m http.server 80 -d swagger uv run python -m http.server 80 -d swagger
seeds:
uv run -m cli.seeds
pytest: pytest:
uv run pytest uv run pytest

View File

@@ -1,3 +1,5 @@
from typing import Any
from aws_lambda_powertools import Logger, Tracer from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.event_handler.api_gateway import ( from aws_lambda_powertools.event_handler.api_gateway import (
APIGatewayHttpResolver, APIGatewayHttpResolver,
@@ -9,7 +11,7 @@ from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing import LambdaContext from aws_lambda_powertools.utilities.typing import LambdaContext
from middlewares import AuthorizerMiddleware from middlewares import AuthorizerMiddleware
from routes import courses, enrollments, lookup, orders, me, users, webhooks from routes import courses, enrollments, lookup, me, orders, users, webhooks
tracer = Tracer() tracer = Tracer()
logger = Logger(__name__) logger = Logger(__name__)
@@ -38,5 +40,5 @@ def exc_error(exc: ServiceError):
@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_HTTP) @logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_HTTP)
@tracer.capture_lambda_handler @tracer.capture_lambda_handler
def lambda_handler(event: dict, context: LambdaContext) -> dict: def lambda_handler(event: dict[str, Any], context: LambdaContext) -> dict[str, Any]:
return app.resolve(event, context) return app.resolve(event, context)

0
http-api/cli/__init__.py Normal file
View File

View File

@@ -19,7 +19,7 @@ collect = DynamoDBCollection(user_layer)
LIMIT = 25 LIMIT = 25
@router.get('/') @router.get('/', include_in_schema=False)
def me(): def me():
user: AuthenticatedUser = router.context['user'] user: AuthenticatedUser = router.context['user']
acls = collect.get_items( acls = collect.get_items(
@@ -37,7 +37,7 @@ def me():
} }
@router.get('/konviva') @router.get('/konviva', include_in_schema=False)
def konviva_(): def konviva_():
user: AuthenticatedUser = router.context['user'] user: AuthenticatedUser = router.context['user']
token = konviva.token(user.email) token = konviva.token(user.email)

View File

@@ -9,12 +9,12 @@ KONVIVA_API_URL: str = os.getenv('KONVIVA_API_URL') # type: ignore
KONVIVA_SECRET_KEY: str = os.getenv('KONVIVA_SECRET_KEY') # type: ignore KONVIVA_SECRET_KEY: str = os.getenv('KONVIVA_SECRET_KEY') # type: ignore
match (os.getenv('AWS_SAM_LOCAL'), os.getenv('ELASTIC_HOSTS')): match os.getenv('AWS_SAM_LOCAL'), os.getenv('ELASTIC_HOSTS'):
case (str() as AWS_SAM_LOCAL, _) if AWS_SAM_LOCAL: case str() as AWS_SAM_LOCAL, _ if AWS_SAM_LOCAL:
ELASTIC_CONN = { ELASTIC_CONN = {
'hosts': 'http://host.docker.internal:9200', 'hosts': 'http://host.docker.internal:9200',
} }
case (_, str() as ELASTIC_HOSTS) if ELASTIC_HOSTS: case _, str() as ELASTIC_HOSTS if ELASTIC_HOSTS:
ELASTIC_CONN = { ELASTIC_CONN = {
'hosts': ELASTIC_HOSTS, 'hosts': ELASTIC_HOSTS,
} }

View File

@@ -42,7 +42,165 @@
} }
], ],
"paths": { "paths": {
"/courses/{id}": {
"get": {
"tags": [
"Course"
],
"summary": "GET /courses/{id}",
"operationId": "get_course_courses__id__get",
"parameters": [
{
"required": true,
"schema": {
"type": "string",
"title": "Id"
},
"name": "id",
"in": "path"
}
],
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
}
},
"/enrollments/{id}": {
"get": {
"tags": [
"Enrollment"
],
"summary": "GET /enrollments/{id}",
"operationId": "get_enrollment_enrollments__id__get",
"parameters": [
{
"required": true,
"schema": {
"type": "string",
"title": "Id"
},
"name": "id",
"in": "path"
}
],
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
},
"patch": {
"tags": [
"Enrollment"
],
"summary": "PATCH /enrollments/{id}",
"operationId": "cancel_enrollments__id__patch",
"parameters": [
{
"required": true,
"schema": {
"type": "string",
"title": "Id"
},
"name": "id",
"in": "path"
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CancelPayload"
}
}
},
"required": true
},
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
}
},
"/users/{id}": { "/users/{id}": {
"get": {
"tags": [
"User"
],
"summary": "Get user",
"operationId": "get_user_users__id__get",
"parameters": [
{
"required": true,
"schema": {
"type": "string",
"title": "Id"
},
"name": "id",
"in": "path"
}
],
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
},
"patch": { "patch": {
"tags": [ "tags": [
"User" "User"
@@ -204,135 +362,13 @@
} }
} }
}, },
"/enrollments/{id}": { "/courses": {
"get": {
"tags": [
"Enrollment"
],
"summary": "GET /enrollments/{id}",
"operationId": "get_enrollment_enrollments__id__get",
"parameters": [
{
"required": true,
"schema": {
"type": "string",
"title": "Id"
},
"name": "id",
"in": "path"
}
],
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
},
"patch": {
"tags": [
"Enrollment"
],
"summary": "PATCH /enrollments/{id}",
"operationId": "cancel_enrollments__id__patch",
"parameters": [
{
"required": true,
"schema": {
"type": "string",
"title": "Id"
},
"name": "id",
"in": "path"
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CancelPayload"
}
}
},
"required": true
},
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
}
},
"/courses/{id}": {
"get": { "get": {
"tags": [ "tags": [
"Course" "Course"
], ],
"summary": "GET /courses/{id}", "summary": "Get courses",
"operationId": "get_course_courses__id__get", "operationId": "get_courses_courses_get",
"parameters": [
{
"required": true,
"schema": {
"type": "string",
"title": "Id"
},
"name": "id",
"in": "path"
}
],
"responses": {
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {}
}
}
}
}
},
"/users": {
"get": {
"tags": [
"User"
],
"summary": "Get users",
"operationId": "get_users_users_get",
"responses": { "responses": {
"422": { "422": {
"description": "Validation Error", "description": "Validation Error",
@@ -354,16 +390,15 @@
}, },
"post": { "post": {
"tags": [ "tags": [
"User" "Course"
], ],
"summary": "POST /users", "summary": "POST /courses",
"description": "Create user", "operationId": "post_course_courses_post",
"operationId": "post_user_users_post",
"requestBody": { "requestBody": {
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"$ref": "#/components/schemas/User" "$ref": "#/components/schemas/CoursePayload"
} }
} }
}, },
@@ -468,13 +503,13 @@
} }
} }
}, },
"/courses": { "/users": {
"get": { "get": {
"tags": [ "tags": [
"Course" "User"
], ],
"summary": "GET /courses", "summary": "Get users",
"operationId": "get_courses_courses_get", "operationId": "get_users_users_get",
"responses": { "responses": {
"422": { "422": {
"description": "Validation Error", "description": "Validation Error",
@@ -496,15 +531,15 @@
}, },
"post": { "post": {
"tags": [ "tags": [
"Course" "User"
], ],
"summary": "POST /courses", "summary": "Create user",
"operationId": "post_course_courses_post", "operationId": "post_user_users_post",
"requestBody": { "requestBody": {
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"$ref": "#/components/schemas/CoursePayload" "$ref": "#/components/schemas/User"
} }
} }
}, },

View File

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

View File

@@ -1,4 +1,4 @@
{"id": {"S": "apikey"}, "sk": {"S": "32504457-f133-4c00-936b-6aa712ca9f40"}, "tenant": {"M": {"id": {"S": "*"}, "name": {"S": "default"}}}} {"id": {"S": "apikey"}, "sk": {"S": "MzI1MDQ0NTctZjEzMy00YzAwLTkzNmItNmFhNzEyY2E5ZjQw"}, "tenant": {"M": {"id": {"S": "*"}, "name": {"S": "default"}}}}
{"id": {"S": "5OxmMjL-ujoR5IMGegQz"}, "sk": {"S": "0"}, "update_date": {"S": "2024-02-08T16:42:33.776409-03:00"}, "create_date": {"S": "2019-03-25T00:00:00-03:00"}, "email_verified": {"BOOL": true}, "cognito:sub": {"S": "58efed8d-d276-41a8-8502-4ab8b5a6415e"}, "cpf": {"S": "07879819908"}, "email": {"S": "sergio@somosbeta.com.br"}, "name": {"S": "S\u00e9rgio Rafael de Siqueira"}, "last_login": {"S": "2024-02-08T20:53:45.818126-03:00"}, "tenant:org_id": {"L": [{"S": "cJtK9SsnJhKPyxESe7g3DG"}]}} {"id": {"S": "5OxmMjL-ujoR5IMGegQz"}, "sk": {"S": "0"}, "update_date": {"S": "2024-02-08T16:42:33.776409-03:00"}, "create_date": {"S": "2019-03-25T00:00:00-03:00"}, "email_verified": {"BOOL": true}, "cognito:sub": {"S": "58efed8d-d276-41a8-8502-4ab8b5a6415e"}, "cpf": {"S": "07879819908"}, "email": {"S": "sergio@somosbeta.com.br"}, "name": {"S": "S\u00e9rgio Rafael de Siqueira"}, "last_login": {"S": "2024-02-08T20:53:45.818126-03:00"}, "tenant:org_id": {"L": [{"S": "cJtK9SsnJhKPyxESe7g3DG"}]}}
{"id": {"S": "5OxmMjL-ujoR5IMGegQz"}, "sk": {"S": "cognito"}, "create_date": {"S": "2025-03-03T17:12:26.443507-03:00"}, "sub": {"S": "58efed8d-d276-41a8-8502-4ab8b5a6415e"}} {"id": {"S": "5OxmMjL-ujoR5IMGegQz"}, "sk": {"S": "cognito"}, "create_date": {"S": "2025-03-03T17:12:26.443507-03:00"}, "sub": {"S": "58efed8d-d276-41a8-8502-4ab8b5a6415e"}}
{"id": {"S": "5OxmMjL-ujoR5IMGegQz"}, "sk": {"S": "emails#sergio@somosbeta.com.br"}, "email_verified": {"BOOL": true}, "update_date": {"S": "2024-02-08T16:42:33.776409-03:00"}, "create_date": {"S": "2019-03-25T00:00:00-03:00"}, "email_primary": {"BOOL": true}, "mx_record_exists": {"BOOL": true}, "update_date": {"S": "2023-11-09T12:13:04.308986-03:00"}} {"id": {"S": "5OxmMjL-ujoR5IMGegQz"}, "sk": {"S": "emails#sergio@somosbeta.com.br"}, "email_verified": {"BOOL": true}, "update_date": {"S": "2024-02-08T16:42:33.776409-03:00"}, "create_date": {"S": "2019-03-25T00:00:00-03:00"}, "email_primary": {"BOOL": true}, "mx_record_exists": {"BOOL": true}, "update_date": {"S": "2023-11-09T12:13:04.308986-03:00"}}

View File

@@ -40,18 +40,27 @@ def test_bearer_apikey(
event = { event = {
'headers': { 'headers': {
'authorization': 'Bearer sk-32504457-f133-4c00-936b-6aa712ca9f40', 'authorization': 'Bearer sk-MzI1MDQ0NTctZjEzMy00YzAwLTkzNmItNmFhNzEyY2E5ZjQw',
} }
} }
# This data was added from seeds # This data was added from seeds
assert app.lambda_handler(event, lambda_context) == { assert app.lambda_handler(event, lambda_context) == {
'isAuthorized': True, 'isAuthorized': True,
'context': {'tenant': {'name': 'default', 'id': '*'}}, 'context': {
'tenant': {
'name': 'default',
'id': '*',
}
},
} }
# This data was added from seeds # This data was added from seeds
assert app.lambda_handler( assert app.lambda_handler(
{'headers': {'authorization': 'Bearer sk-abc'}}, {
'headers': {
'authorization': 'Bearer sk-abc',
}
},
lambda_context, lambda_context,
) == {'isAuthorized': False} ) == {'isAuthorized': False}