3838_event_type_updated = "google.cloud.firestore.document.v1.updated"
3939_event_type_deleted = "google.cloud.firestore.document.v1.deleted"
4040
41+ _event_type_written_with_auth_context = "google.cloud.firestore.document.v1.written.withAuthContext"
42+ _event_type_created_with_auth_context = "google.cloud.firestore.document.v1.created.withAuthContext"
43+ _event_type_updated_with_auth_context = "google.cloud.firestore.document.v1.updated.withAuthContext"
44+ _event_type_deleted_with_auth_context = "google.cloud.firestore.document.v1.deleted.withAuthContext"
45+
4146
4247@_dataclass .dataclass (frozen = True )
4348class Event (_core .CloudEvent [_core .T ]):
@@ -82,9 +87,26 @@ class Event(_core.CloudEvent[_core.T]):
8287_C1 = _typing .Callable [[_E1 ], None ]
8388_C2 = _typing .Callable [[_E2 ], None ]
8489
90+ AuthType = _typing .Literal ["service_account" , "api_key" , "system" ,
91+ "unauthenticated" , "unknown" ]
92+
93+
94+ @_dataclass .dataclass (frozen = True )
95+ class AuthEvent (Event [_core .T ]):
96+ auth_type : AuthType
97+ """The type of principal that triggered the event"""
98+ auth_id : str | None
99+ """The unique identifier for the principal"""
100+
101+
102+ _E3 = AuthEvent [Change [DocumentSnapshot | None ]]
103+ _E4 = AuthEvent [DocumentSnapshot | None ]
104+ _C3 = _typing .Callable [[_E3 ], None ]
105+ _C4 = _typing .Callable [[_E4 ], None ]
106+
85107
86108def _firestore_endpoint_handler (
87- func : _C1 | _C2 ,
109+ func : _C1 | _C2 | _C3 | _C4 ,
88110 event_type : str ,
89111 document_pattern : _path_pattern .PathPattern ,
90112 raw : _ce .CloudEvent ,
@@ -94,12 +116,14 @@ def _firestore_endpoint_handler(
94116 firestore_event_data : _firestore .DocumentEventData
95117 content_type : str = event_attributes ["datacontenttype" ]
96118 if "application/json" in content_type or isinstance (event_data , dict ):
97- firestore_event_data = _firestore .DocumentEventData .from_json (
98- event_data )
119+ firestore_event_data = _typing .cast (
120+ _firestore .DocumentEventData ,
121+ _firestore .DocumentEventData .from_json (event_data ))
99122 elif "application/protobuf" in content_type or isinstance (
100123 event_data , bytes ):
101- firestore_event_data = _firestore .DocumentEventData .deserialize (
102- event_data )
124+ firestore_event_data = _typing .cast (
125+ _firestore .DocumentEventData ,
126+ _firestore .DocumentEventData .deserialize (event_data ))
103127 else :
104128 actual_type = type (event_data )
105129 raise TypeError (f"Firestore: Cannot parse event payload of data type "
@@ -110,6 +134,8 @@ def _firestore_endpoint_handler(
110134 event_namespace = event_attributes ["namespace" ]
111135 event_document = event_attributes ["document" ]
112136 event_database = event_attributes ["database" ]
137+ event_auth_type = event_attributes ["authtype" ]
138+ event_auth_id = event_attributes ["authid" ]
113139
114140 time = event_attributes ["time" ]
115141 event_time = _util .timestamp_conversion (time )
@@ -146,18 +172,23 @@ def _firestore_endpoint_handler(
146172 firestore_event_data .old_value .update_time ,
147173 )
148174 if event_type == _event_type_deleted :
149- firestore_event_data = old_value_snapshot
175+ firestore_event_data = _typing .cast (_firestore .DocumentEventData ,
176+ old_value_snapshot )
150177 if event_type == _event_type_created :
151- firestore_event_data = value_snapshot
178+ firestore_event_data = _typing .cast (_firestore .DocumentEventData ,
179+ value_snapshot )
152180 if event_type in (_event_type_written , _event_type_updated ):
153- firestore_event_data = Change (
154- before = old_value_snapshot ,
155- after = value_snapshot ,
156- )
181+ firestore_event_data = _typing .cast (
182+ _firestore .DocumentEventData ,
183+ Change (
184+ before = old_value_snapshot ,
185+ after = value_snapshot ,
186+ ))
157187
158188 params : dict [str , str ] = {
159189 ** document_pattern .extract_matches (event_document ),
160190 }
191+
161192 database_event = Event (
162193 project = event_project ,
163194 namespace = event_namespace ,
@@ -173,7 +204,15 @@ def _firestore_endpoint_handler(
173204 subject = event_attributes ["subject" ],
174205 params = params ,
175206 )
176- func (database_event )
207+
208+ if event_type .endswith (".withAuthContext" ):
209+ database_event_with_auth_context = AuthEvent (** vars (database_event ),
210+ auth_type = event_auth_type ,
211+ auth_id = event_auth_id )
212+ func (database_event_with_auth_context )
213+ else :
214+ # mypy cannot infer that the event type is correct, hence the cast
215+ _typing .cast (_C1 | _C2 , func )(database_event )
177216
178217
179218@_util .copy_func_kwargs (FirestoreOptions )
@@ -224,6 +263,57 @@ def on_document_written_wrapped(raw: _ce.CloudEvent):
224263 return on_document_written_inner_decorator
225264
226265
266+ @_util .copy_func_kwargs (FirestoreOptions )
267+ def on_document_written_with_auth_context (** kwargs
268+ ) -> _typing .Callable [[_C1 ], _C1 ]:
269+ """
270+ Event handler that triggers when a document is created, updated, or deleted in Firestore.
271+ This trigger will also provide the authentication context of the principal who triggered
272+ the event.
273+
274+ Example:
275+
276+ .. code-block:: python
277+
278+ @on_document_written_with_auth_context(document="*")
279+ def example(event: AuthEvent[Change[DocumentSnapshot]]) -> None:
280+ pass
281+
282+ :param \\ *\\ *kwargs: Firestore options.
283+ :type \\ *\\ *kwargs: as :exc:`firebase_functions.options.FirestoreOptions`
284+ :rtype: :exc:`typing.Callable`
285+ \\ [ \\ [ :exc:`firebase_functions.firestore_fn.AuthEvent` \\ [
286+ :exc:`firebase_functions.db.Change` \\ ] \\ ], `None` \\ ]
287+ A function that takes a Firestore event and returns ``None``.
288+ """
289+ options = FirestoreOptions (** kwargs )
290+
291+ def on_document_written_with_auth_context_inner_decorator (func : _C1 ):
292+ document_pattern = _path_pattern .PathPattern (
293+ _util .normalize_path (options .document ))
294+
295+ @_functools .wraps (func )
296+ def on_document_written_with_auth_context_wrapped (raw : _ce .CloudEvent ):
297+ return _firestore_endpoint_handler (
298+ func ,
299+ _event_type_written_with_auth_context ,
300+ document_pattern ,
301+ raw ,
302+ )
303+
304+ _util .set_func_endpoint_attr (
305+ on_document_written_with_auth_context_wrapped ,
306+ options ._endpoint (
307+ event_type = _event_type_written ,
308+ func_name = func .__name__ ,
309+ document_pattern = document_pattern ,
310+ ),
311+ )
312+ return on_document_written_with_auth_context_wrapped
313+
314+ return on_document_written_with_auth_context_inner_decorator
315+
316+
227317@_util .copy_func_kwargs (FirestoreOptions )
228318def on_document_updated (** kwargs ) -> _typing .Callable [[_C1 ], _C1 ]:
229319 """
@@ -272,6 +362,57 @@ def on_document_updated_wrapped(raw: _ce.CloudEvent):
272362 return on_document_updated_inner_decorator
273363
274364
365+ @_util .copy_func_kwargs (FirestoreOptions )
366+ def on_document_updated_with_auth_context (** kwargs
367+ ) -> _typing .Callable [[_C1 ], _C1 ]:
368+ """
369+ Event handler that triggers when a document is updated in Firestore.
370+ This trigger will also provide the authentication context of the principal who triggered
371+ the event.
372+
373+ Example:
374+
375+ .. code-block:: python
376+
377+ @on_document_updated_with_auth_context(document="*")
378+ def example(event: AuthEvent[Change[DocumentSnapshot]]) -> None:
379+ pass
380+
381+ :param \\ *\\ *kwargs: Firestore options.
382+ :type \\ *\\ *kwargs: as :exc:`firebase_functions.options.FirestoreOptions`
383+ :rtype: :exc:`typing.Callable`
384+ \\ [ \\ [ :exc:`firebase_functions.firestore_fn.AuthEvent` \\ [
385+ :exc:`firebase_functions.db.Change` \\ ] \\ ], `None` \\ ]
386+ A function that takes a Firestore event and returns ``None``.
387+ """
388+ options = FirestoreOptions (** kwargs )
389+
390+ def on_document_updated_with_auth_context_inner_decorator (func : _C1 ):
391+ document_pattern = _path_pattern .PathPattern (
392+ _util .normalize_path (options .document ))
393+
394+ @_functools .wraps (func )
395+ def on_document_updated_with_auth_context_wrapped (raw : _ce .CloudEvent ):
396+ return _firestore_endpoint_handler (
397+ func ,
398+ _event_type_updated_with_auth_context ,
399+ document_pattern ,
400+ raw ,
401+ )
402+
403+ _util .set_func_endpoint_attr (
404+ on_document_updated_with_auth_context_wrapped ,
405+ options ._endpoint (
406+ event_type = _event_type_updated_with_auth_context ,
407+ func_name = func .__name__ ,
408+ document_pattern = document_pattern ,
409+ ),
410+ )
411+ return on_document_updated_with_auth_context_wrapped
412+
413+ return on_document_updated_with_auth_context_inner_decorator
414+
415+
275416@_util .copy_func_kwargs (FirestoreOptions )
276417def on_document_created (** kwargs ) -> _typing .Callable [[_C2 ], _C2 ]:
277418 """
@@ -320,6 +461,57 @@ def on_document_created_wrapped(raw: _ce.CloudEvent):
320461 return on_document_created_inner_decorator
321462
322463
464+ @_util .copy_func_kwargs (FirestoreOptions )
465+ def on_document_created_with_auth_context (** kwargs
466+ ) -> _typing .Callable [[_C2 ], _C2 ]:
467+ """
468+ Event handler that triggers when a document is created in Firestore.
469+ This trigger will also provide the authentication context of the principal who triggered
470+ the event.
471+
472+ Example:
473+
474+ .. code-block:: python
475+
476+ @on_document_created_with_auth_context(document="*")
477+ def example(event: AuthEvent[DocumentSnapshot]):
478+ pass
479+
480+ :param \\ *\\ *kwargs: Firestore options.
481+ :type \\ *\\ *kwargs: as :exc:`firebase_functions.options.FirestoreOptions`
482+ :rtype: :exc:`typing.Callable`
483+ \\ [ \\ [ :exc:`firebase_functions.firestore_fn.AuthEvent` \\ [
484+ :exc:`object` \\ ] \\ ], `None` \\ ]
485+ A function that takes a Firestore event and returns ``None``.
486+ """
487+ options = FirestoreOptions (** kwargs )
488+
489+ def on_document_created_with_auth_context_inner_decorator (func : _C2 ):
490+ document_pattern = _path_pattern .PathPattern (
491+ _util .normalize_path (options .document ))
492+
493+ @_functools .wraps (func )
494+ def on_document_created_with_auth_context_wrapped (raw : _ce .CloudEvent ):
495+ return _firestore_endpoint_handler (
496+ func ,
497+ _event_type_created_with_auth_context ,
498+ document_pattern ,
499+ raw ,
500+ )
501+
502+ _util .set_func_endpoint_attr (
503+ on_document_created_with_auth_context_wrapped ,
504+ options ._endpoint (
505+ event_type = _event_type_created_with_auth_context ,
506+ func_name = func .__name__ ,
507+ document_pattern = document_pattern ,
508+ ),
509+ )
510+ return on_document_created_with_auth_context_wrapped
511+
512+ return on_document_created_with_auth_context_inner_decorator
513+
514+
323515@_util .copy_func_kwargs (FirestoreOptions )
324516def on_document_deleted (** kwargs ) -> _typing .Callable [[_C2 ], _C2 ]:
325517 """
@@ -366,3 +558,54 @@ def on_document_deleted_wrapped(raw: _ce.CloudEvent):
366558 return on_document_deleted_wrapped
367559
368560 return on_document_deleted_inner_decorator
561+
562+
563+ @_util .copy_func_kwargs (FirestoreOptions )
564+ def on_document_deleted_with_auth_context (** kwargs
565+ ) -> _typing .Callable [[_C2 ], _C2 ]:
566+ """
567+ Event handler that triggers when a document is deleted in Firestore.
568+ This trigger will also provide the authentication context of the principal who triggered
569+ the event.
570+
571+ Example:
572+
573+ .. code-block:: python
574+
575+ @on_document_deleted_with_auth_context(document="*")
576+ def example(event: AuthEvent[DocumentSnapshot]) -> None:
577+ pass
578+
579+ :param \\ *\\ *kwargs: Firestore options.
580+ :type \\ *\\ *kwargs: as :exc:`firebase_functions.options.FirestoreOptions`
581+ :rtype: :exc:`typing.Callable`
582+ \\ [ \\ [ :exc:`firebase_functions.firestore_fn.AuthEvent` \\ [
583+ :exc:`object` \\ ] \\ ], `None` \\ ]
584+ A function that takes a Firestore event and returns ``None``.
585+ """
586+ options = FirestoreOptions (** kwargs )
587+
588+ def on_document_deleted_with_auth_context_inner_decorator (func : _C2 ):
589+ document_pattern = _path_pattern .PathPattern (
590+ _util .normalize_path (options .document ))
591+
592+ @_functools .wraps (func )
593+ def on_document_deleted_with_auth_context_wrapped (raw : _ce .CloudEvent ):
594+ return _firestore_endpoint_handler (
595+ func ,
596+ _event_type_deleted_with_auth_context ,
597+ document_pattern ,
598+ raw ,
599+ )
600+
601+ _util .set_func_endpoint_attr (
602+ on_document_deleted_with_auth_context_wrapped ,
603+ options ._endpoint (
604+ event_type = _event_type_deleted_with_auth_context ,
605+ func_name = func .__name__ ,
606+ document_pattern = document_pattern ,
607+ ),
608+ )
609+ return on_document_deleted_with_auth_context_wrapped
610+
611+ return on_document_deleted_with_auth_context_inner_decorator
0 commit comments