|
20 | 20 | import typing as _typing |
21 | 21 | from enum import Enum |
22 | 22 |
|
| 23 | +import cloudevents.http as _ce |
23 | 24 | from flask import ( |
24 | 25 | Request as _Request, |
25 | 26 | ) |
26 | 27 | from flask import ( |
27 | 28 | Response as _Response, |
28 | 29 | ) |
29 | 30 |
|
| 31 | +import firebase_functions.core as _core |
30 | 32 | import firebase_functions.options as _options |
31 | 33 | import firebase_functions.private.util as _util |
| 34 | +from firebase_functions.options import AuthOptions # noqa: F401 |
32 | 35 |
|
33 | 36 |
|
34 | 37 | @_dataclasses.dataclass(frozen=True) |
@@ -62,10 +65,10 @@ class AuthUserMetadata: |
62 | 65 | Additional metadata about the user. |
63 | 66 | """ |
64 | 67 |
|
65 | | - creation_time: _dt.datetime |
| 68 | + creation_time: _dt.datetime | None = None |
66 | 69 | """The date the user was created.""" |
67 | 70 |
|
68 | | - last_sign_in_time: _dt.datetime | None |
| 71 | + last_sign_in_time: _dt.datetime | None = None |
69 | 72 | """The date the user last signed in.""" |
70 | 73 |
|
71 | 74 |
|
@@ -116,7 +119,7 @@ class AuthMultiFactorSettings: |
116 | 119 | @_dataclasses.dataclass(frozen=True) |
117 | 120 | class AuthUserRecord: |
118 | 121 | """ |
119 | | - The UserRecord passed to auth blocking functions from the identity platform. |
| 122 | + The UserRecord passed to auth blocking and event functions from the identity platform. |
120 | 123 | """ |
121 | 124 |
|
122 | 125 | uid: str |
@@ -472,3 +475,120 @@ def before_user_created_wrapped(request: _Request) -> _Response: |
472 | 475 | return before_user_created_wrapped |
473 | 476 |
|
474 | 477 | return before_user_created_decorator |
| 478 | + |
| 479 | + |
| 480 | +@_dataclasses.dataclass(frozen=True) |
| 481 | +class AuthEvent(_core.CloudEvent[AuthUserRecord]): |
| 482 | + """ |
| 483 | + A CloudEvent that contains an AuthUserRecord when a user is created or deleted. |
| 484 | + """ |
| 485 | + |
| 486 | + project: str | None = None |
| 487 | + """ |
| 488 | + The project identifier. |
| 489 | + """ |
| 490 | + |
| 491 | + tenant_id: str | None = None |
| 492 | + """ |
| 493 | + The ID of the Identity Platform tenant associated with the event, if applicable. |
| 494 | + """ |
| 495 | + |
| 496 | + |
| 497 | +AuthEventCallable = _typing.Callable[[AuthEvent], None] |
| 498 | +""" |
| 499 | +The type of the callable for 'on_user_created' and 'on_user_deleted' Auth events. |
| 500 | +""" |
| 501 | + |
| 502 | + |
| 503 | +@_util.copy_func_kwargs(_options.AuthOptions) |
| 504 | +def on_user_created( |
| 505 | + **kwargs, |
| 506 | +) -> _typing.Callable[[AuthEventCallable], AuthEventCallable]: |
| 507 | + """ |
| 508 | + Handles an event that is triggered when a user is created in Firebase Authentication. |
| 509 | +
|
| 510 | + Example: |
| 511 | +
|
| 512 | + .. code-block:: python |
| 513 | +
|
| 514 | + from firebase_functions import identity_fn |
| 515 | +
|
| 516 | + @identity_fn.on_user_created() |
| 517 | + def example(event: identity_fn.AuthEvent) -> None: |
| 518 | + pass |
| 519 | +
|
| 520 | + :param \\*\\*kwargs: Options. |
| 521 | + :type \\*\\*kwargs: as :exc:`firebase_functions.options.AuthOptions` |
| 522 | + :rtype: :exc:`typing.Callable` |
| 523 | + \\[ \\[ :exc:`firebase_functions.identity_fn.AuthEvent` \\], `None` \\] |
| 524 | + A function that takes an AuthEvent and returns ``None``. |
| 525 | + """ |
| 526 | + options = _options.AuthOptions(**kwargs) |
| 527 | + |
| 528 | + def on_user_created_decorator(func: AuthEventCallable): |
| 529 | + from firebase_functions.private._identity_fn import ( |
| 530 | + event_type_user_created, |
| 531 | + user_event_handler, |
| 532 | + ) |
| 533 | + |
| 534 | + @_functools.wraps(func) |
| 535 | + def on_user_created_wrapped(raw: _ce.CloudEvent): |
| 536 | + return user_event_handler(func, raw) |
| 537 | + |
| 538 | + _util.set_func_endpoint_attr( |
| 539 | + on_user_created_wrapped, |
| 540 | + options._endpoint( |
| 541 | + func_name=func.__name__, |
| 542 | + event_type=event_type_user_created, |
| 543 | + ), |
| 544 | + ) |
| 545 | + return on_user_created_wrapped |
| 546 | + |
| 547 | + return on_user_created_decorator |
| 548 | + |
| 549 | + |
| 550 | +@_util.copy_func_kwargs(_options.AuthOptions) |
| 551 | +def on_user_deleted( |
| 552 | + **kwargs, |
| 553 | +) -> _typing.Callable[[AuthEventCallable], AuthEventCallable]: |
| 554 | + """ |
| 555 | + Handles an event that is triggered when a user is deleted in Firebase Authentication. |
| 556 | +
|
| 557 | + Example: |
| 558 | +
|
| 559 | + .. code-block:: python |
| 560 | +
|
| 561 | + from firebase_functions import identity_fn |
| 562 | +
|
| 563 | + @identity_fn.on_user_deleted() |
| 564 | + def example(event: identity_fn.AuthEvent) -> None: |
| 565 | + pass |
| 566 | +
|
| 567 | + :param \\*\\*kwargs: Options. |
| 568 | + :type \\*\\*kwargs: as :exc:`firebase_functions.options.AuthOptions` |
| 569 | + :rtype: :exc:`typing.Callable` |
| 570 | + \\[ \\[ :exc:`firebase_functions.identity_fn.AuthEvent` \\], `None` \\] |
| 571 | + A function that takes an AuthEvent and returns ``None``. |
| 572 | + """ |
| 573 | + options = _options.AuthOptions(**kwargs) |
| 574 | + |
| 575 | + def on_user_deleted_decorator(func: AuthEventCallable): |
| 576 | + from firebase_functions.private._identity_fn import ( |
| 577 | + event_type_user_deleted, |
| 578 | + user_event_handler, |
| 579 | + ) |
| 580 | + |
| 581 | + @_functools.wraps(func) |
| 582 | + def on_user_deleted_wrapped(raw: _ce.CloudEvent): |
| 583 | + return user_event_handler(func, raw) |
| 584 | + |
| 585 | + _util.set_func_endpoint_attr( |
| 586 | + on_user_deleted_wrapped, |
| 587 | + options._endpoint( |
| 588 | + func_name=func.__name__, |
| 589 | + event_type=event_type_user_deleted, |
| 590 | + ), |
| 591 | + ) |
| 592 | + return on_user_deleted_wrapped |
| 593 | + |
| 594 | + return on_user_deleted_decorator |
0 commit comments