add never logged to add user
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
from typing import Generic, Mapping
|
from typing import Generic, Mapping
|
||||||
|
|
||||||
from aws_lambda_powertools.event_handler import content_types
|
from aws_lambda_powertools.event_handler import Response, content_types
|
||||||
from aws_lambda_powertools.event_handler.api_gateway import Response, ResponseT
|
from aws_lambda_powertools.event_handler.api_gateway import ResponseT
|
||||||
|
|
||||||
|
|
||||||
class JSONResponse(Response, Generic[ResponseT]):
|
class JSONResponse(Response, Generic[ResponseT]):
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ COURSE_TABLE: str = os.getenv('COURSE_TABLE') # type: ignore
|
|||||||
BUCKET_NAME: str = os.getenv('BUCKET_NAME') # type: ignore
|
BUCKET_NAME: str = os.getenv('BUCKET_NAME') # type: ignore
|
||||||
|
|
||||||
PAPERFORGE_API = 'https://paperforge.saladeaula.digital'
|
PAPERFORGE_API = 'https://paperforge.saladeaula.digital'
|
||||||
|
|
||||||
|
INTERNAL_EMAIL_DOMAIN = 'users.noreply.saladeaula.digital'
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ from pydantic import BaseModel, EmailStr, Field
|
|||||||
|
|
||||||
from api_gateway import JSONResponse
|
from api_gateway import JSONResponse
|
||||||
from boto3clients import dynamodb_client
|
from boto3clients import dynamodb_client
|
||||||
from config import USER_TABLE
|
from config import INTERNAL_EMAIL_DOMAIN, USER_TABLE
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
dyn = DynamoDBPersistenceLayer(USER_TABLE, dynamodb_client)
|
dyn = DynamoDBPersistenceLayer(USER_TABLE, dynamodb_client)
|
||||||
@@ -33,21 +33,24 @@ class User(BaseModel):
|
|||||||
email: EmailStr
|
email: EmailStr
|
||||||
|
|
||||||
|
|
||||||
class CPFConflictError(Exception): ...
|
class ConflictError(ServiceError):
|
||||||
|
|
||||||
|
|
||||||
class EmailConflictError(Exception): ...
|
|
||||||
|
|
||||||
|
|
||||||
class UserConflictError(ServiceError):
|
|
||||||
def __init__(self, msg: str | dict):
|
def __init__(self, msg: str | dict):
|
||||||
super().__init__(HTTPStatus.CONFLICT, msg)
|
super().__init__(HTTPStatus.CONFLICT, msg)
|
||||||
|
|
||||||
|
|
||||||
class UserMissingError(NotFoundError): ...
|
class CPFConflictError(ConflictError): ...
|
||||||
|
|
||||||
|
|
||||||
class OrgMissingError(NotFoundError): ...
|
class EmailConflictError(ConflictError): ...
|
||||||
|
|
||||||
|
|
||||||
|
class UserConflictError(ConflictError): ...
|
||||||
|
|
||||||
|
|
||||||
|
class UserNotFoundError(NotFoundError): ...
|
||||||
|
|
||||||
|
|
||||||
|
class OrgNotFoundError(NotFoundError): ...
|
||||||
|
|
||||||
|
|
||||||
@router.post('/<org_id>/users')
|
@router.post('/<org_id>/users')
|
||||||
@@ -103,13 +106,13 @@ def unlink(org_id: str, user_id: str):
|
|||||||
def _create_user(user: User, org: Org) -> bool:
|
def _create_user(user: User, org: Org) -> bool:
|
||||||
now_ = now()
|
now_ = now()
|
||||||
user_id = uuid4()
|
user_id = uuid4()
|
||||||
email_verified = '@users.noreply.saladeaula.digital' in user.email
|
email_verified = INTERNAL_EMAIL_DOMAIN in user.email
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with dyn.transact_writer() as transact:
|
with dyn.transact_writer() as transact:
|
||||||
transact.put(
|
transact.put(
|
||||||
item={
|
item=user.model_dump()
|
||||||
**user.model_dump(),
|
| {
|
||||||
'id': user_id,
|
'id': user_id,
|
||||||
'sk': '0',
|
'sk': '0',
|
||||||
'email_verified': email_verified,
|
'email_verified': email_verified,
|
||||||
@@ -119,6 +122,13 @@ def _create_user(user: User, org: Org) -> bool:
|
|||||||
'created_at': now_,
|
'created_at': now_,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
transact.put(
|
||||||
|
item={
|
||||||
|
'id': user_id,
|
||||||
|
'sk': 'NEVER_LOGGED',
|
||||||
|
'created_at': now_,
|
||||||
|
}
|
||||||
|
)
|
||||||
transact.put(
|
transact.put(
|
||||||
item={
|
item={
|
||||||
'id': user_id,
|
'id': user_id,
|
||||||
@@ -188,7 +198,7 @@ def _create_user(user: User, org: Org) -> bool:
|
|||||||
transact.condition(
|
transact.condition(
|
||||||
key=KeyPair(org.id, '0'), # type: ignore
|
key=KeyPair(org.id, '0'), # type: ignore
|
||||||
cond_expr='attribute_exists(sk)',
|
cond_expr='attribute_exists(sk)',
|
||||||
exc_cls=OrgMissingError,
|
exc_cls=OrgNotFoundError,
|
||||||
)
|
)
|
||||||
except (CPFConflictError, EmailConflictError):
|
except (CPFConflictError, EmailConflictError):
|
||||||
return False
|
return False
|
||||||
@@ -202,14 +212,14 @@ def _add_member(user_id: str, org: Org) -> None:
|
|||||||
with dyn.transact_writer() as transact:
|
with dyn.transact_writer() as transact:
|
||||||
transact.update(
|
transact.update(
|
||||||
key=KeyPair(user_id, '0'),
|
key=KeyPair(user_id, '0'),
|
||||||
update_expr='ADD tenant_id :org_id',
|
|
||||||
# Post-migration: uncomment the following line
|
# Post-migration: uncomment the following line
|
||||||
# update_expr='ADD tenant_id :org_id',
|
# update_expr='ADD tenant_id :org_id',
|
||||||
|
update_expr='ADD tenant_id :org_id',
|
||||||
expr_attr_values={
|
expr_attr_values={
|
||||||
':org_id': {org.id},
|
':org_id': {org.id},
|
||||||
},
|
},
|
||||||
cond_expr='attribute_exists(sk)',
|
cond_expr='attribute_exists(sk)',
|
||||||
exc_cls=UserMissingError,
|
exc_cls=UserNotFoundError,
|
||||||
)
|
)
|
||||||
transact.put(
|
transact.put(
|
||||||
item={
|
item={
|
||||||
@@ -234,7 +244,7 @@ def _add_member(user_id: str, org: Org) -> None:
|
|||||||
transact.condition(
|
transact.condition(
|
||||||
key=KeyPair(org.id, '0'), # type: ignore
|
key=KeyPair(org.id, '0'), # type: ignore
|
||||||
cond_expr='attribute_exists(sk)',
|
cond_expr='attribute_exists(sk)',
|
||||||
exc_cls=OrgMissingError,
|
exc_cls=OrgNotFoundError,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -254,6 +264,6 @@ def _get_user_id(user: User) -> str:
|
|||||||
).get('id')
|
).get('id')
|
||||||
|
|
||||||
if not user_id:
|
if not user_id:
|
||||||
raise UserMissingError()
|
raise UserNotFoundError('User not found')
|
||||||
|
|
||||||
return user_id
|
return user_id
|
||||||
|
|||||||
@@ -92,7 +92,6 @@ def update(
|
|||||||
cond_expr='attribute_not_exists(sk)',
|
cond_expr='attribute_not_exists(sk)',
|
||||||
exc_cls=RateLimitExceededError,
|
exc_cls=RateLimitExceededError,
|
||||||
)
|
)
|
||||||
|
|
||||||
transact.update(
|
transact.update(
|
||||||
key=KeyPair(user_id, '0'),
|
key=KeyPair(user_id, '0'),
|
||||||
update_expr='SET #name = :name, cpf = :cpf, updated_at = :now',
|
update_expr='SET #name = :name, cpf = :cpf, updated_at = :now',
|
||||||
|
|||||||
@@ -73,6 +73,16 @@ def add(
|
|||||||
'created_at': now_,
|
'created_at': now_,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
transact.put(
|
||||||
|
item={
|
||||||
|
'id': user_id,
|
||||||
|
'sk': f'EMAIL_VERIFICATION#{uuid4()}',
|
||||||
|
'name': name,
|
||||||
|
'email': email,
|
||||||
|
'ttl': ttl(start_dt=now_, days=30),
|
||||||
|
'created_at': now_,
|
||||||
|
}
|
||||||
|
)
|
||||||
transact.put(
|
transact.put(
|
||||||
item={
|
item={
|
||||||
# Post-migration (users): rename `email` to `EMAIL`
|
# Post-migration (users): rename `email` to `EMAIL`
|
||||||
@@ -84,16 +94,6 @@ def add(
|
|||||||
cond_expr='attribute_not_exists(sk)',
|
cond_expr='attribute_not_exists(sk)',
|
||||||
exc_cls=EmailConflictError,
|
exc_cls=EmailConflictError,
|
||||||
)
|
)
|
||||||
transact.put(
|
|
||||||
item={
|
|
||||||
'id': user_id,
|
|
||||||
'sk': f'EMAIL_VERIFICATION#{uuid4()}',
|
|
||||||
'name': name,
|
|
||||||
'email': email,
|
|
||||||
'ttl': ttl(start_dt=now_, days=30),
|
|
||||||
'created_at': now_,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return JSONResponse(status_code=HTTPStatus.CREATED)
|
return JSONResponse(status_code=HTTPStatus.CREATED)
|
||||||
|
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ def test_org_not_found(
|
|||||||
lambda_context,
|
lambda_context,
|
||||||
)
|
)
|
||||||
body = json.loads(r['body'])
|
body = json.loads(r['body'])
|
||||||
assert body['type'] == 'OrgMissingError'
|
assert body['type'] == 'OrgNotFoundError'
|
||||||
|
|
||||||
|
|
||||||
def test_unlink(
|
def test_unlink(
|
||||||
|
|||||||
@@ -14,15 +14,15 @@ def test_get_emails(
|
|||||||
):
|
):
|
||||||
r = app.lambda_handler(
|
r = app.lambda_handler(
|
||||||
http_api_proxy(
|
http_api_proxy(
|
||||||
raw_path='/users/15bacf02-1535-4bee-9022-19d106fd7518/emails',
|
raw_path="/users/15bacf02-1535-4bee-9022-19d106fd7518/emails",
|
||||||
method=HTTPMethod.GET,
|
method=HTTPMethod.GET,
|
||||||
),
|
),
|
||||||
lambda_context,
|
lambda_context,
|
||||||
)
|
)
|
||||||
assert r['statusCode'] == HTTPStatus.OK
|
assert r["statusCode"] == HTTPStatus.OK
|
||||||
|
|
||||||
body = json.loads(r['body'])
|
body = json.loads(r["body"])
|
||||||
assert len(body['items']) == 2
|
assert len(body["items"]) == 2
|
||||||
|
|
||||||
|
|
||||||
def test_add_email(
|
def test_add_email(
|
||||||
@@ -34,26 +34,26 @@ def test_add_email(
|
|||||||
):
|
):
|
||||||
r = app.lambda_handler(
|
r = app.lambda_handler(
|
||||||
http_api_proxy(
|
http_api_proxy(
|
||||||
raw_path='/users/15bacf02-1535-4bee-9022-19d106fd7518/emails',
|
raw_path="/users/15bacf02-1535-4bee-9022-19d106fd7518/emails",
|
||||||
method=HTTPMethod.POST,
|
method=HTTPMethod.POST,
|
||||||
body={
|
body={
|
||||||
'email': 'osergiosiqueira+pytest@gmail.com',
|
"email": "osergiosiqueira+pytest@gmail.com",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
lambda_context,
|
lambda_context,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert r['statusCode'] == HTTPStatus.CREATED
|
assert r["statusCode"] == HTTPStatus.CREATED
|
||||||
r = dynamodb_persistence_layer.collection.query(
|
r = dynamodb_persistence_layer.collection.query(
|
||||||
KeyPair(
|
KeyPair(
|
||||||
'15bacf02-1535-4bee-9022-19d106fd7518',
|
"15bacf02-1535-4bee-9022-19d106fd7518",
|
||||||
'EMAIL_VERIFICATION',
|
"EMAIL_VERIFICATION",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
items = r['items']
|
items = r["items"]
|
||||||
|
|
||||||
assert len(items) == 2
|
assert len(items) == 2
|
||||||
assert any(x.get('email') == 'osergiosiqueira+pytest@gmail.com' for x in items)
|
assert any(x.get("email") == "osergiosiqueira+pytest@gmail.com" for x in items)
|
||||||
|
|
||||||
|
|
||||||
def test_email_as_primary(
|
def test_email_as_primary(
|
||||||
@@ -65,24 +65,24 @@ def test_email_as_primary(
|
|||||||
):
|
):
|
||||||
r = app.lambda_handler(
|
r = app.lambda_handler(
|
||||||
http_api_proxy(
|
http_api_proxy(
|
||||||
raw_path='/users/15bacf02-1535-4bee-9022-19d106fd7518/emails/primary',
|
raw_path="/users/15bacf02-1535-4bee-9022-19d106fd7518/emails/primary",
|
||||||
method=HTTPMethod.PATCH,
|
method=HTTPMethod.PATCH,
|
||||||
body={
|
body={
|
||||||
'old_email': 'sergio@somosbeta.com.br',
|
"old_email": "sergio@somosbeta.com.br",
|
||||||
'new_email': 'osergiosiqueira@gmail.com',
|
"new_email": "osergiosiqueira@gmail.com",
|
||||||
'email_verified': 'false',
|
"email_verified": "false",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
lambda_context,
|
lambda_context,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert r['statusCode'] == HTTPStatus.NO_CONTENT
|
assert r["statusCode"] == HTTPStatus.NO_CONTENT
|
||||||
|
|
||||||
r = dynamodb_persistence_layer.collection.get_item(
|
r = dynamodb_persistence_layer.collection.get_item(
|
||||||
KeyPair('15bacf02-1535-4bee-9022-19d106fd7518', '0')
|
KeyPair("15bacf02-1535-4bee-9022-19d106fd7518", "0")
|
||||||
)
|
)
|
||||||
assert r['email'] == 'osergiosiqueira@gmail.com'
|
assert r["email"] == "osergiosiqueira@gmail.com"
|
||||||
assert r['emails'] == {'osergiosiqueira@gmail.com', 'sergio@somosbeta.combr'}
|
assert r["emails"] == {"osergiosiqueira@gmail.com", "sergio@somosbeta.combr"}
|
||||||
|
|
||||||
|
|
||||||
def test_verify_email(
|
def test_verify_email(
|
||||||
@@ -93,13 +93,13 @@ def test_verify_email(
|
|||||||
):
|
):
|
||||||
r = app.lambda_handler(
|
r = app.lambda_handler(
|
||||||
http_api_proxy(
|
http_api_proxy(
|
||||||
raw_path='/users/15bacf02-1535-4bee-9022-19d106fd7518/emails/0d29c753-55f8-42d2-908b-e4976aafc183/verify',
|
raw_path="/users/15bacf02-1535-4bee-9022-19d106fd7518/emails/0d29c753-55f8-42d2-908b-e4976aafc183/verify",
|
||||||
method=HTTPMethod.POST,
|
method=HTTPMethod.POST,
|
||||||
),
|
),
|
||||||
lambda_context,
|
lambda_context,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert r['statusCode'] == HTTPStatus.NO_CONTENT
|
assert r["statusCode"] == HTTPStatus.OK
|
||||||
|
|
||||||
|
|
||||||
def test_verify_email_notfound(
|
def test_verify_email_notfound(
|
||||||
@@ -110,13 +110,13 @@ def test_verify_email_notfound(
|
|||||||
):
|
):
|
||||||
r = app.lambda_handler(
|
r = app.lambda_handler(
|
||||||
http_api_proxy(
|
http_api_proxy(
|
||||||
raw_path='/users/15bacf02-1535-4bee-9022-19d106fd7518/emails/abc/verify',
|
raw_path="/users/15bacf02-1535-4bee-9022-19d106fd7518/emails/abc/verify",
|
||||||
method=HTTPMethod.POST,
|
method=HTTPMethod.POST,
|
||||||
),
|
),
|
||||||
lambda_context,
|
lambda_context,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert r['statusCode'] == HTTPStatus.NOT_FOUND
|
assert r["statusCode"] == HTTPStatus.NOT_FOUND
|
||||||
|
|
||||||
|
|
||||||
def test_remove_emal(
|
def test_remove_emal(
|
||||||
@@ -127,10 +127,10 @@ def test_remove_emal(
|
|||||||
):
|
):
|
||||||
r = app.lambda_handler(
|
r = app.lambda_handler(
|
||||||
http_api_proxy(
|
http_api_proxy(
|
||||||
raw_path='/users/15bacf02-1535-4bee-9022-19d106fd7518/emails/osergiosiqueira@gmail.com',
|
raw_path="/users/15bacf02-1535-4bee-9022-19d106fd7518/emails/osergiosiqueira@gmail.com",
|
||||||
method=HTTPMethod.DELETE,
|
method=HTTPMethod.DELETE,
|
||||||
),
|
),
|
||||||
lambda_context,
|
lambda_context,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert r['statusCode'] == HTTPStatus.NO_CONTENT
|
assert r["statusCode"] == HTTPStatus.NO_CONTENT
|
||||||
|
|||||||
Reference in New Issue
Block a user