firebase-functions 0.1.2__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/PKG-INFO +1 -1
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/setup.py +2 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/__init__.py +1 -1
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/alerts_fn.py +2 -2
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/core.py +1 -1
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/db_fn.py +5 -5
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/firestore_fn.py +255 -12
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/https_fn.py +20 -9
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/identity_fn.py +15 -4
- firebase_functions-0.3.0/src/firebase_functions/logger.py +133 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/options.py +15 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/params.py +47 -4
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/private/_alerts_fn.py +13 -2
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/private/_identity_fn.py +29 -8
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/private/manifest.py +8 -3
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/private/path_pattern.py +4 -1
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/private/util.py +53 -13
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/pubsub_fn.py +1 -1
- firebase_functions-0.3.0/src/firebase_functions/py.typed +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/remote_config_fn.py +8 -2
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/storage_fn.py +1 -1
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/tasks_fn.py +5 -2
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/test_lab_fn.py +6 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions.egg-info/PKG-INFO +1 -1
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions.egg-info/SOURCES.txt +4 -0
- firebase_functions-0.3.0/tests/test_firestore_fn.py +72 -0
- firebase_functions-0.3.0/tests/test_logger.py +81 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/tests/test_manifest.py +25 -27
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/tests/test_params.py +36 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/tests/test_tasks_fn.py +35 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/tests/test_util.py +9 -1
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/LICENSE +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/README.md +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/pyproject.toml +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/setup.cfg +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/alerts/__init__.py +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/alerts/app_distribution_fn.py +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/alerts/billing_fn.py +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/alerts/crashlytics_fn.py +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/alerts/performance_fn.py +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/eventarc_fn.py +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/private/__init__.py +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/private/serving.py +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/private/token_verifier.py +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/scheduler_fn.py +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions.egg-info/dependency_links.txt +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions.egg-info/requires.txt +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions.egg-info/top_level.txt +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/tests/test_eventarc_fn.py +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/tests/test_options.py +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/tests/test_path_pattern.py +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/tests/test_pubsub_fn.py +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/tests/test_remote_config_fn.py +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/tests/test_scheduler_fn.py +0 -0
- {firebase_functions-0.1.2 → firebase_functions-0.3.0}/tests/test_test_lab_fn.py +0 -0
|
@@ -56,6 +56,8 @@ setup(
|
|
|
56
56
|
extras_require={'dev': dev_requires},
|
|
57
57
|
packages=find_packages(where='src'),
|
|
58
58
|
package_dir={'': 'src'},
|
|
59
|
+
include_package_data=True,
|
|
60
|
+
package_data={'firebase_functions': ['py.typed']},
|
|
59
61
|
python_requires='>=3.10',
|
|
60
62
|
classifiers=[
|
|
61
63
|
'Development Status :: 4 - Beta',
|
|
@@ -46,7 +46,7 @@ class AlertEvent(_CloudEvent[T]):
|
|
|
46
46
|
app_id: str | None
|
|
47
47
|
"""
|
|
48
48
|
The Firebase App ID that's associated with the alert. This is optional,
|
|
49
|
-
and only present when the alert is targeting
|
|
49
|
+
and only present when the alert is targeting a specific Firebase App.
|
|
50
50
|
"""
|
|
51
51
|
|
|
52
52
|
|
|
@@ -66,7 +66,7 @@ def on_alert_published(
|
|
|
66
66
|
**kwargs
|
|
67
67
|
) -> _typing.Callable[[OnAlertPublishedCallable], OnAlertPublishedCallable]:
|
|
68
68
|
"""
|
|
69
|
-
Event handler
|
|
69
|
+
Event handler that triggers when a Firebase Alerts event is published.
|
|
70
70
|
|
|
71
71
|
Example:
|
|
72
72
|
|
|
@@ -25,7 +25,7 @@ T = _typing.TypeVar("T")
|
|
|
25
25
|
class CloudEvent(_typing.Generic[T]):
|
|
26
26
|
"""
|
|
27
27
|
A CloudEvent is the base of a cross-platform format for encoding a serverless event.
|
|
28
|
-
More information can be found at https://github.com/cloudevents/spec
|
|
28
|
+
More information can be found at https://github.com/cloudevents/spec.
|
|
29
29
|
"""
|
|
30
30
|
|
|
31
31
|
specversion: str
|
|
@@ -61,7 +61,7 @@ class Event(_core.CloudEvent[T]):
|
|
|
61
61
|
|
|
62
62
|
params: dict[str, str]
|
|
63
63
|
"""
|
|
64
|
-
|
|
64
|
+
A dict containing the values of the path patterns.
|
|
65
65
|
Only named capture groups are populated - {key}, {key=*}, {key=**}
|
|
66
66
|
"""
|
|
67
67
|
|
|
@@ -125,7 +125,7 @@ def _db_endpoint_handler(
|
|
|
125
125
|
@_util.copy_func_kwargs(DatabaseOptions)
|
|
126
126
|
def on_value_written(**kwargs) -> _typing.Callable[[_C1], _C1]:
|
|
127
127
|
"""
|
|
128
|
-
Event handler
|
|
128
|
+
Event handler that triggers when data is created, updated, or deleted in Realtime Database.
|
|
129
129
|
|
|
130
130
|
Example:
|
|
131
131
|
|
|
@@ -175,7 +175,7 @@ def on_value_written(**kwargs) -> _typing.Callable[[_C1], _C1]:
|
|
|
175
175
|
@_util.copy_func_kwargs(DatabaseOptions)
|
|
176
176
|
def on_value_updated(**kwargs) -> _typing.Callable[[_C1], _C1]:
|
|
177
177
|
"""
|
|
178
|
-
Event handler
|
|
178
|
+
Event handler that triggers when data is updated in Realtime Database.
|
|
179
179
|
|
|
180
180
|
Example:
|
|
181
181
|
|
|
@@ -225,7 +225,7 @@ def on_value_updated(**kwargs) -> _typing.Callable[[_C1], _C1]:
|
|
|
225
225
|
@_util.copy_func_kwargs(DatabaseOptions)
|
|
226
226
|
def on_value_created(**kwargs) -> _typing.Callable[[_C2], _C2]:
|
|
227
227
|
"""
|
|
228
|
-
Event handler
|
|
228
|
+
Event handler that triggers when data is created in Realtime Database.
|
|
229
229
|
|
|
230
230
|
Example:
|
|
231
231
|
|
|
@@ -275,7 +275,7 @@ def on_value_created(**kwargs) -> _typing.Callable[[_C2], _C2]:
|
|
|
275
275
|
@_util.copy_func_kwargs(DatabaseOptions)
|
|
276
276
|
def on_value_deleted(**kwargs) -> _typing.Callable[[_C2], _C2]:
|
|
277
277
|
"""
|
|
278
|
-
Event handler
|
|
278
|
+
Event handler that triggers when data is deleted in Realtime Database.
|
|
279
279
|
|
|
280
280
|
Example:
|
|
281
281
|
|
{firebase_functions-0.1.2 → firebase_functions-0.3.0}/src/firebase_functions/firestore_fn.py
RENAMED
|
@@ -38,6 +38,11 @@ _event_type_created = "google.cloud.firestore.document.v1.created"
|
|
|
38
38
|
_event_type_updated = "google.cloud.firestore.document.v1.updated"
|
|
39
39
|
_event_type_deleted = "google.cloud.firestore.document.v1.deleted"
|
|
40
40
|
|
|
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
|
+
|
|
41
46
|
|
|
42
47
|
@_dataclass.dataclass(frozen=True)
|
|
43
48
|
class Event(_core.CloudEvent[_core.T]):
|
|
@@ -82,9 +87,26 @@ _E2 = Event[DocumentSnapshot | None]
|
|
|
82
87
|
_C1 = _typing.Callable[[_E1], None]
|
|
83
88
|
_C2 = _typing.Callable[[_E2], None]
|
|
84
89
|
|
|
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
|
+
|
|
85
107
|
|
|
86
108
|
def _firestore_endpoint_handler(
|
|
87
|
-
func: _C1 | _C2,
|
|
109
|
+
func: _C1 | _C2 | _C3 | _C4,
|
|
88
110
|
event_type: str,
|
|
89
111
|
document_pattern: _path_pattern.PathPattern,
|
|
90
112
|
raw: _ce.CloudEvent,
|
|
@@ -94,12 +116,14 @@ def _firestore_endpoint_handler(
|
|
|
94
116
|
firestore_event_data: _firestore.DocumentEventData
|
|
95
117
|
content_type: str = event_attributes["datacontenttype"]
|
|
96
118
|
if "application/json" in content_type or isinstance(event_data, dict):
|
|
97
|
-
firestore_event_data =
|
|
98
|
-
|
|
119
|
+
firestore_event_data = _typing.cast(
|
|
120
|
+
_firestore.DocumentEventData,
|
|
121
|
+
_firestore.DocumentEventData.from_json(event_data))
|
|
99
122
|
elif "application/protobuf" in content_type or isinstance(
|
|
100
123
|
event_data, bytes):
|
|
101
|
-
firestore_event_data =
|
|
102
|
-
|
|
124
|
+
firestore_event_data = _typing.cast(
|
|
125
|
+
_firestore.DocumentEventData,
|
|
126
|
+
_firestore.DocumentEventData.deserialize(event_data))
|
|
103
127
|
else:
|
|
104
128
|
actual_type = type(event_data)
|
|
105
129
|
raise TypeError(f"Firestore: Cannot parse event payload of data type "
|
|
@@ -110,6 +134,8 @@ def _firestore_endpoint_handler(
|
|
|
110
134
|
event_namespace = event_attributes["namespace"]
|
|
111
135
|
event_document = event_attributes["document"]
|
|
112
136
|
event_database = event_attributes["database"]
|
|
137
|
+
event_auth_type = event_attributes["authtype"]
|
|
138
|
+
event_auth_id = event_attributes["authid"]
|
|
113
139
|
|
|
114
140
|
time = event_attributes["time"]
|
|
115
141
|
event_time = _util.timestamp_conversion(time)
|
|
@@ -146,18 +172,23 @@ def _firestore_endpoint_handler(
|
|
|
146
172
|
firestore_event_data.old_value.update_time,
|
|
147
173
|
)
|
|
148
174
|
if event_type == _event_type_deleted:
|
|
149
|
-
firestore_event_data =
|
|
175
|
+
firestore_event_data = _typing.cast(_firestore.DocumentEventData,
|
|
176
|
+
old_value_snapshot)
|
|
150
177
|
if event_type == _event_type_created:
|
|
151
|
-
firestore_event_data =
|
|
178
|
+
firestore_event_data = _typing.cast(_firestore.DocumentEventData,
|
|
179
|
+
value_snapshot)
|
|
152
180
|
if event_type in (_event_type_written, _event_type_updated):
|
|
153
|
-
firestore_event_data =
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
181
|
+
firestore_event_data = _typing.cast(
|
|
182
|
+
_firestore.DocumentEventData,
|
|
183
|
+
Change(
|
|
184
|
+
before=old_value_snapshot,
|
|
185
|
+
after=value_snapshot,
|
|
186
|
+
))
|
|
157
187
|
|
|
158
188
|
params: dict[str, str] = {
|
|
159
189
|
**document_pattern.extract_matches(event_document),
|
|
160
190
|
}
|
|
191
|
+
|
|
161
192
|
database_event = Event(
|
|
162
193
|
project=event_project,
|
|
163
194
|
namespace=event_namespace,
|
|
@@ -173,7 +204,15 @@ def _firestore_endpoint_handler(
|
|
|
173
204
|
subject=event_attributes["subject"],
|
|
174
205
|
params=params,
|
|
175
206
|
)
|
|
176
|
-
|
|
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)
|
|
177
216
|
|
|
178
217
|
|
|
179
218
|
@_util.copy_func_kwargs(FirestoreOptions)
|
|
@@ -224,6 +263,57 @@ def on_document_written(**kwargs) -> _typing.Callable[[_C1], _C1]:
|
|
|
224
263
|
return on_document_written_inner_decorator
|
|
225
264
|
|
|
226
265
|
|
|
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
|
+
|
|
227
317
|
@_util.copy_func_kwargs(FirestoreOptions)
|
|
228
318
|
def on_document_updated(**kwargs) -> _typing.Callable[[_C1], _C1]:
|
|
229
319
|
"""
|
|
@@ -272,6 +362,57 @@ def on_document_updated(**kwargs) -> _typing.Callable[[_C1], _C1]:
|
|
|
272
362
|
return on_document_updated_inner_decorator
|
|
273
363
|
|
|
274
364
|
|
|
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
|
+
|
|
275
416
|
@_util.copy_func_kwargs(FirestoreOptions)
|
|
276
417
|
def on_document_created(**kwargs) -> _typing.Callable[[_C2], _C2]:
|
|
277
418
|
"""
|
|
@@ -320,6 +461,57 @@ def on_document_created(**kwargs) -> _typing.Callable[[_C2], _C2]:
|
|
|
320
461
|
return on_document_created_inner_decorator
|
|
321
462
|
|
|
322
463
|
|
|
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
|
+
|
|
323
515
|
@_util.copy_func_kwargs(FirestoreOptions)
|
|
324
516
|
def on_document_deleted(**kwargs) -> _typing.Callable[[_C2], _C2]:
|
|
325
517
|
"""
|
|
@@ -366,3 +558,54 @@ def on_document_deleted(**kwargs) -> _typing.Callable[[_C2], _C2]:
|
|
|
366
558
|
return on_document_deleted_wrapped
|
|
367
559
|
|
|
368
560
|
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
|
|
@@ -119,9 +119,9 @@ class FunctionsErrorCode(str, _enum.Enum):
|
|
|
119
119
|
|
|
120
120
|
INTERNAL = "internal"
|
|
121
121
|
"""
|
|
122
|
-
Internal errors. Means some invariants expected by
|
|
122
|
+
Internal errors. Means some invariants expected by the
|
|
123
123
|
underlying system have been broken. If you see one of these errors,
|
|
124
|
-
something is
|
|
124
|
+
something is severely broken.
|
|
125
125
|
"""
|
|
126
126
|
|
|
127
127
|
UNAVAILABLE = "unavailable"
|
|
@@ -135,6 +135,9 @@ class FunctionsErrorCode(str, _enum.Enum):
|
|
|
135
135
|
Unrecoverable data loss or corruption.
|
|
136
136
|
"""
|
|
137
137
|
|
|
138
|
+
def __str__(self) -> str:
|
|
139
|
+
return self.value
|
|
140
|
+
|
|
138
141
|
|
|
139
142
|
class _CanonicalErrorCodeName(str, _enum.Enum):
|
|
140
143
|
"""The canonical error code name for a given error code."""
|
|
@@ -157,6 +160,9 @@ class _CanonicalErrorCodeName(str, _enum.Enum):
|
|
|
157
160
|
UNAVAILABLE = "UNAVAILABLE"
|
|
158
161
|
DATA_LOSS = "DATA_LOSS"
|
|
159
162
|
|
|
163
|
+
def __str__(self) -> str:
|
|
164
|
+
return self.value
|
|
165
|
+
|
|
160
166
|
|
|
161
167
|
@_dataclasses.dataclass(frozen=True)
|
|
162
168
|
class _HttpErrorCode:
|
|
@@ -280,7 +286,7 @@ class AuthData:
|
|
|
280
286
|
The interface for Auth tokens verified in Callable functions
|
|
281
287
|
"""
|
|
282
288
|
|
|
283
|
-
uid: str
|
|
289
|
+
uid: str | None
|
|
284
290
|
"""
|
|
285
291
|
User ID of the ID token.
|
|
286
292
|
"""
|
|
@@ -346,8 +352,10 @@ _C1 = _typing.Callable[[Request], Response]
|
|
|
346
352
|
_C2 = _typing.Callable[[CallableRequest[_typing.Any]], _typing.Any]
|
|
347
353
|
|
|
348
354
|
|
|
349
|
-
def _on_call_handler(func: _C2,
|
|
350
|
-
|
|
355
|
+
def _on_call_handler(func: _C2,
|
|
356
|
+
request: Request,
|
|
357
|
+
enforce_app_check: bool,
|
|
358
|
+
verify_token: bool = True) -> Response:
|
|
351
359
|
try:
|
|
352
360
|
if not _util.valid_on_call_request(request):
|
|
353
361
|
_logging.error("Invalid request, unable to process.")
|
|
@@ -357,7 +365,8 @@ def _on_call_handler(func: _C2, request: Request,
|
|
|
357
365
|
data=_json.loads(request.data)["data"],
|
|
358
366
|
)
|
|
359
367
|
|
|
360
|
-
token_status = _util.on_call_check_tokens(request
|
|
368
|
+
token_status = _util.on_call_check_tokens(request,
|
|
369
|
+
verify_token=verify_token)
|
|
361
370
|
|
|
362
371
|
if token_status.auth == _util.OnCallTokenState.INVALID:
|
|
363
372
|
raise HttpsError(FunctionsErrorCode.UNAUTHENTICATED,
|
|
@@ -377,8 +386,10 @@ def _on_call_handler(func: _C2, request: Request,
|
|
|
377
386
|
if token_status.auth_token is not None:
|
|
378
387
|
context = _dataclasses.replace(
|
|
379
388
|
context,
|
|
380
|
-
auth=AuthData(
|
|
381
|
-
|
|
389
|
+
auth=AuthData(
|
|
390
|
+
token_status.auth_token["uid"]
|
|
391
|
+
if "uid" in token_status.auth_token else None,
|
|
392
|
+
token_status.auth_token),
|
|
382
393
|
)
|
|
383
394
|
|
|
384
395
|
instance_id = request.headers.get("Firebase-Instance-ID-Token")
|
|
@@ -399,7 +410,7 @@ def _on_call_handler(func: _C2, request: Request,
|
|
|
399
410
|
# pylint: disable=broad-except
|
|
400
411
|
except Exception as err:
|
|
401
412
|
if not isinstance(err, HttpsError):
|
|
402
|
-
_logging.error("Unhandled error", err)
|
|
413
|
+
_logging.error("Unhandled error: %s", err)
|
|
403
414
|
err = HttpsError(FunctionsErrorCode.INTERNAL, "INTERNAL")
|
|
404
415
|
status = err._http_error_code.status
|
|
405
416
|
return _make_response(_jsonify(error=err._as_dict()), status)
|
|
@@ -36,7 +36,7 @@ class AuthUserInfo:
|
|
|
36
36
|
"""The user identifier for the linked provider."""
|
|
37
37
|
|
|
38
38
|
provider_id: str
|
|
39
|
-
"""The linked provider ID (
|
|
39
|
+
"""The linked provider ID (such as "google.com" for the Google provider)."""
|
|
40
40
|
|
|
41
41
|
display_name: str | None = None
|
|
42
42
|
"""The display name for the linked provider."""
|
|
@@ -110,7 +110,7 @@ class AuthMultiFactorSettings:
|
|
|
110
110
|
@_dataclasses.dataclass(frozen=True)
|
|
111
111
|
class AuthUserRecord:
|
|
112
112
|
"""
|
|
113
|
-
The UserRecord passed to auth blocking
|
|
113
|
+
The UserRecord passed to auth blocking functions from the identity platform.
|
|
114
114
|
"""
|
|
115
115
|
|
|
116
116
|
uid: str
|
|
@@ -155,7 +155,7 @@ class AuthUserRecord:
|
|
|
155
155
|
|
|
156
156
|
provider_data: list[AuthUserInfo]
|
|
157
157
|
"""
|
|
158
|
-
An array of providers (
|
|
158
|
+
An array of providers (such as Google or Facebook) linked to the user.
|
|
159
159
|
"""
|
|
160
160
|
|
|
161
161
|
password_hash: str | None
|
|
@@ -203,6 +203,9 @@ class AdditionalUserInfo:
|
|
|
203
203
|
is_new_user: bool
|
|
204
204
|
"""A boolean indicating if the user is new or not."""
|
|
205
205
|
|
|
206
|
+
recaptcha_score: float | None
|
|
207
|
+
"""The user's reCAPTCHA score, if available."""
|
|
208
|
+
|
|
206
209
|
|
|
207
210
|
@_dataclasses.dataclass(frozen=True)
|
|
208
211
|
class Credential:
|
|
@@ -243,7 +246,7 @@ class AuthBlockingEvent:
|
|
|
243
246
|
|
|
244
247
|
data: AuthUserRecord
|
|
245
248
|
"""
|
|
246
|
-
The UserRecord passed to auth blocking
|
|
249
|
+
The UserRecord passed to auth blocking functions from the identity platform.
|
|
247
250
|
"""
|
|
248
251
|
|
|
249
252
|
locale: str | None
|
|
@@ -282,6 +285,12 @@ class AuthBlockingEvent:
|
|
|
282
285
|
The time the event was triggered."""
|
|
283
286
|
|
|
284
287
|
|
|
288
|
+
RecaptchaActionOptions = _typing.Literal["ALLOW", "BLOCK"]
|
|
289
|
+
"""
|
|
290
|
+
The reCAPTCHA action options.
|
|
291
|
+
"""
|
|
292
|
+
|
|
293
|
+
|
|
285
294
|
class BeforeCreateResponse(_typing.TypedDict, total=False):
|
|
286
295
|
"""
|
|
287
296
|
The handler response type for 'before_user_created' blocking events.
|
|
@@ -302,6 +311,8 @@ class BeforeCreateResponse(_typing.TypedDict, total=False):
|
|
|
302
311
|
custom_claims: dict[str, _typing.Any] | None
|
|
303
312
|
"""The user's custom claims object if available."""
|
|
304
313
|
|
|
314
|
+
recaptcha_action_override: RecaptchaActionOptions | None
|
|
315
|
+
|
|
305
316
|
|
|
306
317
|
class BeforeSignInResponse(BeforeCreateResponse, total=False):
|
|
307
318
|
"""
|