diff --git a/src/conode/application/attach_node_to_group/attach_node.py b/src/conode/application/attach_node_to_group/attach_node.py index 5cbbae3..2add15a 100644 --- a/src/conode/application/attach_node_to_group/attach_node.py +++ b/src/conode/application/attach_node_to_group/attach_node.py @@ -32,9 +32,9 @@ class AttachNodeInteractor: company_repository: CompanyRepository async def execute(self, request: AttachNodeRequestDTO) -> list[NodeAssociation]: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: group = await self.group_repository.get_by_id(request.group_id) request_nodes = set(request.nodes) diff --git a/src/conode/application/detach_node_from_group/detach_node.py b/src/conode/application/detach_node_from_group/detach_node.py index 36c2eac..5f3616b 100644 --- a/src/conode/application/detach_node_from_group/detach_node.py +++ b/src/conode/application/detach_node_from_group/detach_node.py @@ -24,9 +24,9 @@ class DetachNodeInteractor: company_repository: CompanyRepository async def execute(self, association_id: NodeAssociationId) -> None: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: association = await self.node_association_repository.get_by_id( association_id, ) diff --git a/src/conode/application/interfaces/token_manager/token_manager.py b/src/conode/application/interfaces/token_manager/token_manager.py index 5d67513..7121a9d 100644 --- a/src/conode/application/interfaces/token_manager/token_manager.py +++ b/src/conode/application/interfaces/token_manager/token_manager.py @@ -9,6 +9,7 @@ class UserMeta(TypedDict): last_name: str email: str username: str + email_verified: bool class TokenManagerResponse(NamedTuple): diff --git a/src/conode/application/manage_company/update_company.py b/src/conode/application/manage_company/update_company.py index 8b0d31b..5e22dec 100644 --- a/src/conode/application/manage_company/update_company.py +++ b/src/conode/application/manage_company/update_company.py @@ -21,9 +21,9 @@ class UpdateCompanyInteractor: async def execute( self, company_id: CompanyId, request: UpdateCompanyRequestDTO ) -> None: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: company = await self.company_repository.get_by_id(company_id) await self.access_control_service.ensure_user_can_manipulate_company( diff --git a/src/conode/application/manage_context/create_context.py b/src/conode/application/manage_context/create_context.py index 8e5fc77..b24b4ec 100644 --- a/src/conode/application/manage_context/create_context.py +++ b/src/conode/application/manage_context/create_context.py @@ -26,9 +26,9 @@ class CreateContextInteractor: access_control_service: AccessControlService async def execute(self, request: CreateContextRequestDTO) -> Context: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: company = await self.company_repository.get_by_id(request.company_id) await self.access_control_service.ensure_user_can_create_contexts( diff --git a/src/conode/application/manage_context/delete_context.py b/src/conode/application/manage_context/delete_context.py index b98d86a..8adcb07 100644 --- a/src/conode/application/manage_context/delete_context.py +++ b/src/conode/application/manage_context/delete_context.py @@ -17,9 +17,9 @@ class DeleteContextInteractor: transaction_manager: TransactionManager async def execute(self, context_id: ContextId) -> None: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: context = await self.context_repository.get_by_id(context_id) await self.access_control_service.ensure_user_can_manipulate_context( diff --git a/src/conode/application/manage_edge/create_edge.py b/src/conode/application/manage_edge/create_edge.py index 45e0ded..90706fd 100644 --- a/src/conode/application/manage_edge/create_edge.py +++ b/src/conode/application/manage_edge/create_edge.py @@ -37,9 +37,9 @@ class CreateEdgeInteractor: edge_repository: EdgeRepository async def execute(self, request: CreateEdgeRequestDTO) -> Edge: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: context = await self.context_repository.get_by_id(request.context_id) company = await self.company_repository.get_by_id(context.company_id) diff --git a/src/conode/application/manage_edge/delete_edge.py b/src/conode/application/manage_edge/delete_edge.py index 0ca6a4b..bbef042 100644 --- a/src/conode/application/manage_edge/delete_edge.py +++ b/src/conode/application/manage_edge/delete_edge.py @@ -19,8 +19,9 @@ class DeleteEdgeInteractor: context_repository: ContextRepository async def execute(self, edge_id: EdgeId) -> None: + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() edge = await self.edge_repository.get_by_id(edge_id) context = await self.context_repository.get_by_id(edge.context_id) diff --git a/src/conode/application/manage_group/create_group.py b/src/conode/application/manage_group/create_group.py index 53414e5..831cd1f 100644 --- a/src/conode/application/manage_group/create_group.py +++ b/src/conode/application/manage_group/create_group.py @@ -27,9 +27,9 @@ class CreateGroupInteractor: access_control_service: AccessControlService async def execute(self, request: CreateGroupRequestDTO) -> Group: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: company = await self.company_repository.get_by_id(request.company_id) await self.access_control_service.ensure_user_can_create_groups( diff --git a/src/conode/application/manage_group/delete_group.py b/src/conode/application/manage_group/delete_group.py index cd04f3a..8beaad3 100644 --- a/src/conode/application/manage_group/delete_group.py +++ b/src/conode/application/manage_group/delete_group.py @@ -17,9 +17,9 @@ class DeleteGroupInteractor: access_control_service: AccessControlService async def execute(self, group_id: GroupId) -> None: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: group = await self.group_repository.get_by_id(group_id) await self.access_control_service.ensure_user_can_manipulate_group( diff --git a/src/conode/application/manage_node/create_node.py b/src/conode/application/manage_node/create_node.py index 49e31b6..3ab9d4f 100644 --- a/src/conode/application/manage_node/create_node.py +++ b/src/conode/application/manage_node/create_node.py @@ -30,9 +30,9 @@ class CreateNodeInteractor: access_control_service: AccessControlService async def execute(self, request: CreateNodeRequestDTO) -> Node: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: group = await self.group_repository.get_by_id(request.group_id) company = await self.company_repository.get_by_id(group.company_id) diff --git a/src/conode/application/manage_node/delete_node.py b/src/conode/application/manage_node/delete_node.py index 6fe8753..90ef0e1 100644 --- a/src/conode/application/manage_node/delete_node.py +++ b/src/conode/application/manage_node/delete_node.py @@ -21,9 +21,9 @@ class DeleteNodeInteractor: access_control_service: AccessControlService async def execute(self, node_id: NodeId) -> None: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: node = await self.node_repository.get_by_id(node_id) existing_associations = ( diff --git a/src/conode/application/manage_profile/update_current_user_profile.py b/src/conode/application/manage_profile/update_current_user_profile.py index ec8a3a8..b50ebf4 100644 --- a/src/conode/application/manage_profile/update_current_user_profile.py +++ b/src/conode/application/manage_profile/update_current_user_profile.py @@ -20,9 +20,9 @@ class UpdateCurrentUserProfileInteractor: access_control_service: AccessControlService async def execute(self, request: UpdateCurrentUserProfileRequestDTO) -> None: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: user.update_profile( first_name=request.first_name, last_name=request.last_name, diff --git a/src/conode/application/manage_profile/update_user_profile.py b/src/conode/application/manage_profile/update_user_profile.py index 79c6a13..d6a04ff 100644 --- a/src/conode/application/manage_profile/update_user_profile.py +++ b/src/conode/application/manage_profile/update_user_profile.py @@ -23,9 +23,9 @@ class UpdateUserProfileInteractor: async def execute( self, user_id: UserId, request: UpdateUserProfileRequestDTO ) -> None: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: if user.id == user_id: target = user else: diff --git a/src/conode/application/manage_role/create_role.py b/src/conode/application/manage_role/create_role.py index b0bd9fa..e161586 100644 --- a/src/conode/application/manage_role/create_role.py +++ b/src/conode/application/manage_role/create_role.py @@ -42,9 +42,9 @@ class CreateRoleInteractor: role_permissions_repository: RolePermissionsRepository async def execute(self, request: CreateRoleRequestDTO) -> Role: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: company = await self.company_repository.get_by_id(request.company_id) await self.access_control_service.ensure_user_can_create_roles( diff --git a/src/conode/application/manage_role/delete_role.py b/src/conode/application/manage_role/delete_role.py index 5a83e37..97ce91a 100644 --- a/src/conode/application/manage_role/delete_role.py +++ b/src/conode/application/manage_role/delete_role.py @@ -13,9 +13,9 @@ class DeleteRoleInteractor: access_control_service: AccessControlService async def execute(self, role_id: RoleId) -> None: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: role = await self.role_repository.get_by_id(role_id) await self.access_control_service.ensure_user_can_manipulate_role( diff --git a/src/conode/application/manage_role/update_role.py b/src/conode/application/manage_role/update_role.py index fe2460c..b73b046 100644 --- a/src/conode/application/manage_role/update_role.py +++ b/src/conode/application/manage_role/update_role.py @@ -45,9 +45,9 @@ class UpdateRoleInteractor: role_repository: RoleRepository async def execute(self, request: UpdateRoleRequestDTO) -> UpdateRoleResponseDTO: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: role = await self.role_repository.get_by_id(request.role_id) await self.access_control_service.ensure_user_can_manipulate_role( diff --git a/src/conode/application/register_company/register_company.py b/src/conode/application/register_company/register_company.py index d5cbfdd..ffd39fe 100644 --- a/src/conode/application/register_company/register_company.py +++ b/src/conode/application/register_company/register_company.py @@ -34,9 +34,9 @@ class RegisterCompanyInteractor: role_repository: RoleRepository async def execute(self, request: RegisterCompanyRequestDTO) -> Company: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: company = Company.new( company_id=CompanyId(uuid4()), name=request.name, diff --git a/src/conode/application/services/access_control.py b/src/conode/application/services/access_control.py index d58be3e..69adff1 100644 --- a/src/conode/application/services/access_control.py +++ b/src/conode/application/services/access_control.py @@ -25,7 +25,7 @@ RolePermission, RolePermissionEntityId, ) -from conode.domain.user import Email, User, UserId, UserSystemRole +from conode.domain.user import Email, User, UserId type RolesPermissions = list[RolePermission] @@ -55,8 +55,8 @@ async def get_authorized_user(self) -> User: meta = self.identity_provider.get_current_user_meta() user = await self.user_repository.get_by_email(Email(meta["email"])) - if user is None: - async with self.transaction_manager: + async with self.transaction_manager: + if user is None: user = User.new( user_id=UserId(uuid4()), first_name=meta["first_name"], @@ -67,6 +67,9 @@ async def get_authorized_user(self) -> User: ) await self.user_repository.create(user) + user.email_verified = meta["email_verified"] + await self.user_repository.update(user) + return user def check( diff --git a/src/conode/application/share_graph/accept_offer.py b/src/conode/application/share_graph/accept_offer.py index c1642fe..af38e44 100644 --- a/src/conode/application/share_graph/accept_offer.py +++ b/src/conode/application/share_graph/accept_offer.py @@ -44,8 +44,9 @@ class AcceptOfferInteractor: offer_context_repository: OfferContextRepository async def execute(self, offer_id: OfferId) -> Contract: + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() offer = await self.offer_repository.get_by_id(offer_id) offer_from_company, offer_to_company = await self._get_offer_companies( diff --git a/src/conode/application/share_graph/decline_offer.py b/src/conode/application/share_graph/decline_offer.py index a57ae2f..f6b5a8a 100644 --- a/src/conode/application/share_graph/decline_offer.py +++ b/src/conode/application/share_graph/decline_offer.py @@ -22,9 +22,9 @@ class DeclineOfferInteractor: company_repository: CompanyRepository async def execute(self, offer_id: OfferId) -> None: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: offer = await self.offer_repository.get_by_id(offer_id) company = await self.company_repository.get_by_id(offer.to_company_id) diff --git a/src/conode/application/share_graph/send_offer_to_company.py b/src/conode/application/share_graph/send_offer_to_company.py index fd67456..fa108a4 100644 --- a/src/conode/application/share_graph/send_offer_to_company.py +++ b/src/conode/application/share_graph/send_offer_to_company.py @@ -51,9 +51,9 @@ class SendOfferToCompanyInteractor: context_repository: ContextRepository async def execute(self, request: SendOfferToCompanyRequestDTO) -> Offer: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: from_company, to_company = ( await self.company_repository.get_by_id(request.from_company_id), await self.company_repository.get_by_id(request.to_company_id), diff --git a/src/conode/application/update_edge_weight/decrement_edge_weight.py b/src/conode/application/update_edge_weight/decrement_edge_weight.py index eda3fd3..44161f9 100644 --- a/src/conode/application/update_edge_weight/decrement_edge_weight.py +++ b/src/conode/application/update_edge_weight/decrement_edge_weight.py @@ -19,9 +19,9 @@ class DecrementEdgeWeightInteractor: access_control_service: AccessControlService async def execute(self, edge_id: EdgeId) -> None: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: edge = await self.edge_repository.get_by_id(edge_id) context = await self.context_repository.get_by_id(edge.context_id) diff --git a/src/conode/application/update_edge_weight/increment_edge_weight.py b/src/conode/application/update_edge_weight/increment_edge_weight.py index 39ee4f1..d980849 100644 --- a/src/conode/application/update_edge_weight/increment_edge_weight.py +++ b/src/conode/application/update_edge_weight/increment_edge_weight.py @@ -19,9 +19,9 @@ class IncrementEdgeWeightInteractor: context_repository: ContextRepository async def execute(self, edge_id: EdgeId) -> None: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: edge = await self.edge_repository.get_by_id(edge_id) context = await self.context_repository.get_by_id(edge.context_id) diff --git a/src/conode/application/update_edge_weight/update_edge_weight.py b/src/conode/application/update_edge_weight/update_edge_weight.py index d4bb09d..4544236 100644 --- a/src/conode/application/update_edge_weight/update_edge_weight.py +++ b/src/conode/application/update_edge_weight/update_edge_weight.py @@ -19,9 +19,9 @@ class UpdateEdgeWeightInteractor: context_repository: ContextRepository async def execute(self, edge_id: EdgeId, weight: float) -> None: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: edge = await self.edge_repository.get_by_id(edge_id) context = await self.context_repository.get_by_id(edge.context_id) diff --git a/src/conode/application/update_node/update_node.py b/src/conode/application/update_node/update_node.py index 23ab72f..801d1c5 100644 --- a/src/conode/application/update_node/update_node.py +++ b/src/conode/application/update_node/update_node.py @@ -28,9 +28,9 @@ class UpdateNodeInteractor: transaction_manager: TransactionManager async def execute(self, request: UpdateNodeRequestDTO) -> None: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: node = await self.node_repository.get_by_id(request.node_id) existing_associations = ( diff --git a/src/conode/application/verify_company/verify_company.py b/src/conode/application/verify_company/verify_company.py index 1f11aba..3fdc4a6 100644 --- a/src/conode/application/verify_company/verify_company.py +++ b/src/conode/application/verify_company/verify_company.py @@ -16,9 +16,9 @@ class VerifyCompanyInteractor: access_control_service: AccessControlService async def execute(self, company_id: CompanyId) -> None: - async with self.transaction_manager: - user = await self.access_control_service.get_authorized_user() + user = await self.access_control_service.get_authorized_user() + async with self.transaction_manager: self.access_control_service.ensure_user_can_verify_companies(user) company = await self.company_repository.get_by_id(company_id) diff --git a/src/conode/domain/user/model.py b/src/conode/domain/user/model.py index 226ea83..0a597b3 100644 --- a/src/conode/domain/user/model.py +++ b/src/conode/domain/user/model.py @@ -115,6 +115,7 @@ class User(Entity[UserId]): first_name: FirstName last_name: LastName username: Username + email_verified: bool email: Email bio: Bio @@ -135,6 +136,7 @@ def new( last_name=LastName(last_name), username=Username(username), email=Email(email), + email_verified=False, system_role=UserSystemRole.USER, created_at=now, updated_at=now, diff --git a/src/conode/infrastructure/persistence/migrations/versions/d196baf978b0_email_flag.py b/src/conode/infrastructure/persistence/migrations/versions/d196baf978b0_email_flag.py new file mode 100644 index 0000000..c7244d7 --- /dev/null +++ b/src/conode/infrastructure/persistence/migrations/versions/d196baf978b0_email_flag.py @@ -0,0 +1,32 @@ +"""email-flag + +Revision ID: d196baf978b0 +Revises: 4574d0b1f6b0 +Create Date: 2026-08-11 15:58:28.896881 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = 'd196baf978b0' +down_revision: Union[str, Sequence[str], None] = '4574d0b1f6b0' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + """Upgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('user_record', sa.Column('email_verified', sa.Boolean(), nullable=False)) + # ### end Alembic commands ### + + +def downgrade() -> None: + """Downgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('user_record', 'email_verified') + # ### end Alembic commands ### diff --git a/src/conode/infrastructure/persistence/registry.py b/src/conode/infrastructure/persistence/registry.py index 715bd78..3e8def9 100644 --- a/src/conode/infrastructure/persistence/registry.py +++ b/src/conode/infrastructure/persistence/registry.py @@ -59,6 +59,7 @@ Column("username", UsernameType, nullable=False), Column("last_name", LastNameType, nullable=False), Column("first_name", FirstNameType, nullable=False), + Column("email_verified", Boolean, nullable=False), Column("email", EmailType, nullable=False), Column("bio", BioType, nullable=False), Column("created_at", DateTime(timezone=True), nullable=False), diff --git a/src/conode/infrastructure/repositories/user.py b/src/conode/infrastructure/repositories/user.py index 3ef661c..7ce68b2 100644 --- a/src/conode/infrastructure/repositories/user.py +++ b/src/conode/infrastructure/repositories/user.py @@ -25,6 +25,7 @@ async def create(self, user: User) -> None: last_name=user.last_name, username=user.username, email=user.email, + email_verified=user.email_verified, bio=user.bio, created_at=user.created_at, updated_at=user.updated_at, @@ -40,6 +41,7 @@ async def update(self, user: User) -> None: ) .values( system_role=user.system_role, + email_verified=user.email_verified, first_name=user.first_name, last_name=user.last_name, username=user.username, diff --git a/src/conode/infrastructure/token_manager.py b/src/conode/infrastructure/token_manager.py index ba26c2c..83a34fd 100644 --- a/src/conode/infrastructure/token_manager.py +++ b/src/conode/infrastructure/token_manager.py @@ -35,5 +35,6 @@ def decode(self, token: str) -> UserMeta: first_name=payload["given_name"], last_name=payload["family_name"], username=payload["preferred_username"], + email_verified=payload["email_verified"], system_role=role, ) diff --git a/src/conode/presentation/schemas/user.py b/src/conode/presentation/schemas/user.py index 51cc019..2e8167c 100644 --- a/src/conode/presentation/schemas/user.py +++ b/src/conode/presentation/schemas/user.py @@ -70,6 +70,7 @@ class UserSchema(BaseModel): username: str first_name: str last_name: str + email_verified: bool email: EmailStr bio: str diff --git a/src/conode/presentation/views/user.py b/src/conode/presentation/views/user.py index c674088..68a6f76 100644 --- a/src/conode/presentation/views/user.py +++ b/src/conode/presentation/views/user.py @@ -68,6 +68,7 @@ async def get_current_user_profile( return UserSchema( id=result.id, username=result.username.value, + email_verified=result.email_verified, first_name=result.first_name.value, last_name=result.last_name.value, email=result.email.value, @@ -85,6 +86,7 @@ async def get_user_by_username( return UserSchema( id=result.id, username=result.username.value, + email_verified=result.email_verified, first_name=result.first_name.value, last_name=result.last_name.value, email=result.email.value, diff --git a/tests/conftest.py b/tests/conftest.py index 1901153..0d49c92 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,6 @@ from collections.abc import AsyncIterator from dataclasses import dataclass from types import TracebackType -from unittest.mock import AsyncMock import jwt import pytest @@ -84,6 +83,7 @@ def decode(self, token: str) -> UserMeta: email=payload["email"], first_name=payload["given_name"], last_name=payload["family_name"], + email_verified=payload["email_verified"], username=payload["preferred_username"], system_role=role, ) @@ -94,6 +94,7 @@ def encode(self, user: User, *, admin: bool = False) -> str: "email": user.email.value, "given_name": user.first_name.value, "family_name": user.last_name.value, + "email_verified": user.email_verified, "preferred_username": user.username.value, "resource_access": { "realm-management": {"roles": ["realm-admin" if admin else "user"]} @@ -269,7 +270,6 @@ async def session(config: Config) -> AsyncIterator[AsyncSession]: ) async with AsyncSession(engine) as session: - session.commit = AsyncMock() # type: ignore yield session await session.close() diff --git a/tests/e2e/user/test_verified_email.py b/tests/e2e/user/test_verified_email.py new file mode 100644 index 0000000..b6aed28 --- /dev/null +++ b/tests/e2e/user/test_verified_email.py @@ -0,0 +1,29 @@ +from http import HTTPStatus + +import pytest +from httpx import AsyncClient + +from tests.factories.common import authorization_headers +from tests.factories.models import UserFactory + + +@pytest.mark.asyncio +async def test_update_verified_flag_after_request_ok( + transport: AsyncClient, user_factory: UserFactory +) -> None: + user = await user_factory.build() + + response = await transport.get( + "users/me/profile", headers=authorization_headers(user.access_token) + ) + assert response.status_code == HTTPStatus.OK + assert not response.json()["email_verified"] + + user.user.email_verified = True + user.access_token = user_factory.generate_access_token(user.user) + + response = await transport.get( + "users/me/profile", headers=authorization_headers(user.access_token) + ) + assert response.status_code == HTTPStatus.OK + assert response.json()["email_verified"] diff --git a/tests/factories/models/user.py b/tests/factories/models/user.py index 06ea098..02a29bd 100644 --- a/tests/factories/models/user.py +++ b/tests/factories/models/user.py @@ -22,6 +22,9 @@ class UserFactory: user_repository: UserRepository password_hasher: PasswordHasher + def generate_access_token(self, user: User) -> str: + return self.token_manager.encode(user) + async def build(self, *, admin: bool = False) -> UserFactoryResponse: async with self.transaction_manager: user = User.new( @@ -46,5 +49,5 @@ async def build(self, *, admin: bool = False) -> UserFactoryResponse: return UserFactoryResponse( user=user, - access_token=self.token_manager.encode(user), + access_token=self.generate_access_token(user), )