firebase-functions 0.2.0__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.2.0 → firebase_functions-0.3.0}/PKG-INFO +1 -1
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/setup.py +2 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/__init__.py +1 -1
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/firestore_fn.py +255 -12
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/https_fn.py +18 -7
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/logger.py +3 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/options.py +15 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/params.py +44 -1
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/private/_alerts_fn.py +13 -2
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/private/manifest.py +8 -3
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/private/path_pattern.py +4 -1
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/private/util.py +51 -13
- firebase_functions-0.3.0/src/firebase_functions/py.typed +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/remote_config_fn.py +6 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/tasks_fn.py +4 -1
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/test_lab_fn.py +6 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions.egg-info/PKG-INFO +1 -1
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions.egg-info/SOURCES.txt +2 -0
- firebase_functions-0.3.0/tests/test_firestore_fn.py +72 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/tests/test_manifest.py +25 -27
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/tests/test_params.py +36 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/tests/test_tasks_fn.py +35 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/tests/test_util.py +9 -1
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/LICENSE +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/README.md +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/pyproject.toml +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/setup.cfg +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/alerts/__init__.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/alerts/app_distribution_fn.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/alerts/billing_fn.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/alerts/crashlytics_fn.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/alerts/performance_fn.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/alerts_fn.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/core.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/db_fn.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/eventarc_fn.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/identity_fn.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/private/__init__.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/private/_identity_fn.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/private/serving.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/private/token_verifier.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/pubsub_fn.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/scheduler_fn.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/storage_fn.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions.egg-info/dependency_links.txt +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions.egg-info/requires.txt +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions.egg-info/top_level.txt +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/tests/test_eventarc_fn.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/tests/test_logger.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/tests/test_options.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/tests/test_path_pattern.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/tests/test_pubsub_fn.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/tests/test_remote_config_fn.py +0 -0
- {firebase_functions-0.2.0 → firebase_functions-0.3.0}/tests/test_scheduler_fn.py +0 -0
- {firebase_functions-0.2.0 → 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',
|
{firebase_functions-0.2.0 → 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
|
|
@@ -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)
|
|
@@ -41,6 +41,9 @@ class VpcEgressSetting(str, _enum.Enum):
|
|
|
41
41
|
PRIVATE_RANGES_ONLY = "PRIVATE_RANGES_ONLY"
|
|
42
42
|
ALL_TRAFFIC = "ALL_TRAFFIC"
|
|
43
43
|
|
|
44
|
+
def __str__(self) -> str:
|
|
45
|
+
return self.value
|
|
46
|
+
|
|
44
47
|
|
|
45
48
|
class IngressSetting(str, _enum.Enum):
|
|
46
49
|
"""What kind of traffic can access the function."""
|
|
@@ -49,6 +52,9 @@ class IngressSetting(str, _enum.Enum):
|
|
|
49
52
|
ALLOW_INTERNAL_ONLY = "ALLOW_INTERNAL_ONLY"
|
|
50
53
|
ALLOW_INTERNAL_AND_GCLB = "ALLOW_INTERNAL_AND_GCLB"
|
|
51
54
|
|
|
55
|
+
def __str__(self) -> str:
|
|
56
|
+
return self.value
|
|
57
|
+
|
|
52
58
|
|
|
53
59
|
@_dataclasses.dataclass(frozen=True)
|
|
54
60
|
class CorsOptions:
|
|
@@ -88,6 +94,9 @@ class MemoryOption(int, _enum.Enum):
|
|
|
88
94
|
GB_16 = 16 << 10
|
|
89
95
|
GB_32 = 32 << 10
|
|
90
96
|
|
|
97
|
+
def __str__(self) -> str:
|
|
98
|
+
return f"{self.value}MB"
|
|
99
|
+
|
|
91
100
|
|
|
92
101
|
class SupportedRegion(str, _enum.Enum):
|
|
93
102
|
"""
|
|
@@ -120,6 +129,9 @@ class SupportedRegion(str, _enum.Enum):
|
|
|
120
129
|
US_WEST3 = "us-west3"
|
|
121
130
|
US_WEST4 = "us-west4"
|
|
122
131
|
|
|
132
|
+
def __str__(self) -> str:
|
|
133
|
+
return self.value
|
|
134
|
+
|
|
123
135
|
|
|
124
136
|
@_dataclasses.dataclass(frozen=True)
|
|
125
137
|
class RateLimits():
|
|
@@ -587,6 +599,9 @@ class AlertType(str, _enum.Enum):
|
|
|
587
599
|
Performance threshold alerts.
|
|
588
600
|
"""
|
|
589
601
|
|
|
602
|
+
def __str__(self) -> str:
|
|
603
|
+
return self.value
|
|
604
|
+
|
|
590
605
|
|
|
591
606
|
@_dataclasses.dataclass(frozen=True, kw_only=True)
|
|
592
607
|
class FirebaseAlertOptions(EventHandlerOptions):
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"""Module for params that can make Cloud Functions codebases generic."""
|
|
15
15
|
|
|
16
16
|
import abc as _abc
|
|
17
|
+
import json as _json
|
|
17
18
|
import dataclasses as _dataclasses
|
|
18
19
|
import os as _os
|
|
19
20
|
import re as _re
|
|
@@ -139,6 +140,18 @@ class SelectInput(_typing.Generic[_T]):
|
|
|
139
140
|
"""A list of user selectable options."""
|
|
140
141
|
|
|
141
142
|
|
|
143
|
+
@_dataclasses.dataclass(frozen=True)
|
|
144
|
+
class MultiSelectInput():
|
|
145
|
+
"""
|
|
146
|
+
Specifies that a Param's value should be determined by having the user select
|
|
147
|
+
a subset from a list of pre-canned options interactively at deploy-time.
|
|
148
|
+
Will result in errors if used on Params of type other than string[].
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
options: list[SelectOption[str]]
|
|
152
|
+
"""A list of user selectable options."""
|
|
153
|
+
|
|
154
|
+
|
|
142
155
|
@_dataclasses.dataclass(frozen=True)
|
|
143
156
|
class TextInput:
|
|
144
157
|
"""
|
|
@@ -168,6 +181,9 @@ class ResourceType(str, _enum.Enum):
|
|
|
168
181
|
"""The type of resource that a picker should pick."""
|
|
169
182
|
STORAGE_BUCKET = "storage.googleapis.com/Bucket"
|
|
170
183
|
|
|
184
|
+
def __str__(self) -> str:
|
|
185
|
+
return self.value
|
|
186
|
+
|
|
171
187
|
|
|
172
188
|
@_dataclasses.dataclass(frozen=True)
|
|
173
189
|
class ResourceInput:
|
|
@@ -215,7 +231,8 @@ class Param(Expression[_T]):
|
|
|
215
231
|
deployments.
|
|
216
232
|
"""
|
|
217
233
|
|
|
218
|
-
input: TextInput | ResourceInput | SelectInput[
|
|
234
|
+
input: TextInput | ResourceInput | SelectInput[
|
|
235
|
+
_T] | MultiSelectInput | None = None
|
|
219
236
|
"""
|
|
220
237
|
The type of input that is required for this param, e.g. TextInput.
|
|
221
238
|
"""
|
|
@@ -355,6 +372,32 @@ class BoolParam(Param[bool]):
|
|
|
355
372
|
return False
|
|
356
373
|
|
|
357
374
|
|
|
375
|
+
@_dataclasses.dataclass(frozen=True)
|
|
376
|
+
class ListParam(Param[list]):
|
|
377
|
+
"""A parameter as a list of strings."""
|
|
378
|
+
|
|
379
|
+
@property
|
|
380
|
+
def value(self) -> list[str]:
|
|
381
|
+
if _os.environ.get(self.name) is not None:
|
|
382
|
+
# If the environment variable starts with "[" and ends with "]",
|
|
383
|
+
# then assume it is a JSON array and try to parse it.
|
|
384
|
+
# (This is for Cloud Run (v2 Functions), the environment variable is a JSON array.)
|
|
385
|
+
if _os.environ[self.name].startswith("[") and _os.environ[
|
|
386
|
+
self.name].endswith("]"):
|
|
387
|
+
try:
|
|
388
|
+
return _json.loads(_os.environ[self.name])
|
|
389
|
+
except _json.JSONDecodeError:
|
|
390
|
+
return []
|
|
391
|
+
# Otherwise, split the string by commas.
|
|
392
|
+
# (This is for emulator & the Firebase CLI generated .env file, the environment
|
|
393
|
+
# variable is a comma-separated list.)
|
|
394
|
+
return list(filter(len, _os.environ[self.name].split(",")))
|
|
395
|
+
if self.default is not None:
|
|
396
|
+
return self.default.value if isinstance(
|
|
397
|
+
self.default, Expression) else self.default
|
|
398
|
+
return []
|
|
399
|
+
|
|
400
|
+
|
|
358
401
|
@_dataclasses.dataclass(frozen=True)
|
|
359
402
|
class _DefaultStringParam(StringParam):
|
|
360
403
|
"""
|
{firebase_functions-0.2.0 → firebase_functions-0.3.0}/src/firebase_functions/private/_alerts_fn.py
RENAMED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
# pylint: disable=protected-access,cyclic-import
|
|
17
17
|
import typing as _typing
|
|
18
18
|
import cloudevents.http as _ce
|
|
19
|
-
import util as _util
|
|
19
|
+
import firebase_functions.private.util as _util
|
|
20
20
|
from firebase_functions.alerts import FirebaseAlertData
|
|
21
21
|
|
|
22
22
|
from functions_framework import logging as _logging
|
|
@@ -110,6 +110,7 @@ def regression_alert_payload_from_ce_payload(payload: dict):
|
|
|
110
110
|
|
|
111
111
|
def trending_issue_details_from_ce_payload(payload: dict):
|
|
112
112
|
from firebase_functions.alerts.crashlytics_fn import TrendingIssueDetails
|
|
113
|
+
|
|
113
114
|
return TrendingIssueDetails(
|
|
114
115
|
type=payload["type"],
|
|
115
116
|
issue=issue_from_ce_payload(payload["issue"]),
|
|
@@ -120,16 +121,19 @@ def trending_issue_details_from_ce_payload(payload: dict):
|
|
|
120
121
|
|
|
121
122
|
def stability_digest_payload_from_ce_payload(payload: dict):
|
|
122
123
|
from firebase_functions.alerts.crashlytics_fn import StabilityDigestPayload
|
|
124
|
+
|
|
123
125
|
return StabilityDigestPayload(
|
|
124
126
|
digest_date=_util.timestamp_conversion(payload["digestDate"]),
|
|
125
127
|
trending_issues=[
|
|
126
128
|
trending_issue_details_from_ce_payload(issue)
|
|
127
129
|
for issue in payload["trendingIssues"]
|
|
128
|
-
]
|
|
130
|
+
],
|
|
131
|
+
)
|
|
129
132
|
|
|
130
133
|
|
|
131
134
|
def velocity_alert_payload_from_ce_payload(payload: dict):
|
|
132
135
|
from firebase_functions.alerts.crashlytics_fn import VelocityAlertPayload
|
|
136
|
+
|
|
133
137
|
return VelocityAlertPayload(
|
|
134
138
|
issue=issue_from_ce_payload(payload["issue"]),
|
|
135
139
|
create_time=_util.timestamp_conversion(payload["createTime"]),
|
|
@@ -141,11 +145,13 @@ def velocity_alert_payload_from_ce_payload(payload: dict):
|
|
|
141
145
|
|
|
142
146
|
def new_anr_issue_payload_from_ce_payload(payload: dict):
|
|
143
147
|
from firebase_functions.alerts.crashlytics_fn import NewAnrIssuePayload
|
|
148
|
+
|
|
144
149
|
return NewAnrIssuePayload(issue=issue_from_ce_payload(payload["issue"]))
|
|
145
150
|
|
|
146
151
|
|
|
147
152
|
def firebase_alert_data_from_ce(event_dict: dict,) -> FirebaseAlertData:
|
|
148
153
|
from firebase_functions.options import AlertType
|
|
154
|
+
|
|
149
155
|
alert_type: str = event_dict["alerttype"]
|
|
150
156
|
alert_payload = event_dict["payload"]
|
|
151
157
|
if alert_type == AlertType.CRASHLYTICS_NEW_FATAL_ISSUE.value:
|
|
@@ -205,24 +211,29 @@ def event_from_ce_helper(raw: _ce.CloudEvent, cls, app_id=True):
|
|
|
205
211
|
|
|
206
212
|
def billing_event_from_ce(raw: _ce.CloudEvent):
|
|
207
213
|
from firebase_functions.alerts.billing_fn import BillingEvent
|
|
214
|
+
|
|
208
215
|
return event_from_ce_helper(raw, BillingEvent, app_id=False)
|
|
209
216
|
|
|
210
217
|
|
|
211
218
|
def performance_event_from_ce(raw: _ce.CloudEvent):
|
|
212
219
|
from firebase_functions.alerts.performance_fn import PerformanceEvent
|
|
220
|
+
|
|
213
221
|
return event_from_ce_helper(raw, PerformanceEvent)
|
|
214
222
|
|
|
215
223
|
|
|
216
224
|
def app_distribution_event_from_ce(raw: _ce.CloudEvent):
|
|
217
225
|
from firebase_functions.alerts.app_distribution_fn import AppDistributionEvent
|
|
226
|
+
|
|
218
227
|
return event_from_ce_helper(raw, AppDistributionEvent)
|
|
219
228
|
|
|
220
229
|
|
|
221
230
|
def crashlytics_event_from_ce(raw: _ce.CloudEvent):
|
|
222
231
|
from firebase_functions.alerts.crashlytics_fn import CrashlyticsEvent
|
|
232
|
+
|
|
223
233
|
return event_from_ce_helper(raw, CrashlyticsEvent)
|
|
224
234
|
|
|
225
235
|
|
|
226
236
|
def alerts_event_from_ce(raw: _ce.CloudEvent):
|
|
227
237
|
from firebase_functions.alerts_fn import AlertEvent
|
|
238
|
+
|
|
228
239
|
return event_from_ce_helper(raw, AlertEvent)
|