Validates an invitation based on the provided token and email. This function attempts to retrieve an Invitation object using the given `invitation_token` and `email`. It performs several checks to ensure that the invitation is valid, not expired, and in the correct state for accept
(
invitation_token: str, email: str, raise_not_found=False
)
| 476 | |
| 477 | |
| 478 | def validate_invitation( |
| 479 | invitation_token: str, email: str, raise_not_found=False |
| 480 | ) -> Invitation: |
| 481 | """ |
| 482 | Validates an invitation based on the provided token and email. |
| 483 | |
| 484 | This function attempts to retrieve an Invitation object using the given |
| 485 | `invitation_token` and `email`. It performs several checks to ensure that |
| 486 | the invitation is valid, not expired, and in the correct state for acceptance. |
| 487 | |
| 488 | Args: |
| 489 | invitation_token (str): The token associated with the invitation. |
| 490 | email (str): The email address associated with the invitation. |
| 491 | raise_not_found (bool, optional): If True, raises a `NotFound` exception |
| 492 | when the invitation is not found. If False, raises a `ValidationError`. |
| 493 | Defaults to False. |
| 494 | |
| 495 | Returns: |
| 496 | Invitation: The validated Invitation object. |
| 497 | |
| 498 | Raises: |
| 499 | NotFound: If `raise_not_found` is True and the invitation does not exist. |
| 500 | ValidationError: If the invitation does not exist and `raise_not_found` |
| 501 | is False, or if the invitation is invalid or in an incorrect state. |
| 502 | InvitationTokenExpiredException: If the invitation has expired. |
| 503 | |
| 504 | Notes: |
| 505 | - This function uses the admin database connector to bypass RLS protection |
| 506 | since the invitation may belong to a tenant the user is not a member of yet. |
| 507 | - If the invitation has expired, its state is updated to EXPIRED, and an |
| 508 | `InvitationTokenExpiredException` is raised. |
| 509 | - Only invitations in the PENDING state can be accepted. |
| 510 | |
| 511 | Examples: |
| 512 | invitation = validate_invitation("TOKEN123", "user@example.com") |
| 513 | """ |
| 514 | try: |
| 515 | # Admin DB connector is used to bypass RLS protection since the invitation belongs to a tenant the user |
| 516 | # is not a member of yet |
| 517 | invitation = Invitation.objects.using(MainRouter.admin_db).get( |
| 518 | token=invitation_token, email__iexact=email |
| 519 | ) |
| 520 | except Invitation.DoesNotExist: |
| 521 | if raise_not_found: |
| 522 | raise NotFound(detail="Invitation is not valid.") |
| 523 | else: |
| 524 | raise ValidationError({"invitation_token": "Invalid invitation code."}) |
| 525 | |
| 526 | # Check if the invitation has expired |
| 527 | if invitation.expires_at < datetime.now(UTC): |
| 528 | invitation.state = Invitation.State.EXPIRED |
| 529 | invitation.save(using=MainRouter.admin_db) |
| 530 | raise InvitationTokenExpiredException() |
| 531 | |
| 532 | # Check the state of the invitation |
| 533 | if invitation.state != Invitation.State.PENDING: |
| 534 | raise ValidationError( |
| 535 | {"invitation_token": "This invitation is no longer valid."} |