velocity-python 0.1.20__tar.gz → 0.1.22__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.
- {velocity_python-0.1.20/src/velocity_python.egg-info → velocity_python-0.1.22}/PKG-INFO +1 -1
- {velocity_python-0.1.20 → velocity_python-0.1.22}/pyproject.toml +1 -1
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/__init__.py +1 -1
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/__init__.py +20 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/amplify_build.py +1 -1
- velocity_python-0.1.22/src/velocity/aws/s3.py +175 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22/src/velocity_python.egg-info}/PKG-INFO +1 -1
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity_python.egg-info/SOURCES.txt +1 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/LICENSE +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/README.md +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/setup.cfg +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/amplify.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/handlers/__init__.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/handlers/base_handler.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/handlers/context.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/handlers/context_factory.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/handlers/exceptions.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/handlers/lambda_handler.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/handlers/perf.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/handlers/response.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/handlers/sqs_handler.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/tests/__init__.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/tests/test_response.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/__init__.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/core/__init__.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/core/async_support.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/core/column.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/core/database.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/core/decorators.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/core/engine.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/core/result.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/core/row.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/core/sequence.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/core/table.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/core/transaction.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/core/view.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/exceptions.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/migrations.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/__init__.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/base/__init__.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/base/initializer.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/base/operators.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/base/sql.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/base/types.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/mysql/__init__.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/mysql/operators.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/mysql/reserved.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/mysql/sql.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/mysql/types.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/postgres/__init__.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/postgres/operators.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/postgres/reserved.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/postgres/sql.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/postgres/types.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/sqlite/__init__.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/sqlite/operators.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/sqlite/reserved.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/sqlite/sql.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/sqlite/types.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/sqlserver/operators.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/sqlserver/sql.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/sqlserver/types.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/tablehelper.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/__init__.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/common_db_test.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/__init__.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/common.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_column.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_connections.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_database.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_engine.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_imports.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_result.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_row.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_table.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/sql/__init__.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/sql/common.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/test_db_utils.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/test_postgres.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/test_result_caching.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/test_sql_builder.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/test_tablehelper.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/test_view_helper.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/utils.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/logging.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/__init__.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/conv/__init__.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/conv/iconv.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/conv/oconv.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/db.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/export.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/format.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/mail.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/merge.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/pdf.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/tests/__init__.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/tests/test_db.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/tests/test_fix.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/tests/test_format.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/tests/test_iconv.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/tests/test_merge.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/tests/test_oconv.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/tests/test_original_error.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/tests/test_timer.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/timer.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/tools.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/payment/__init__.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/payment/authorizenet_adapter.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/payment/base_adapter.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/payment/braintree_adapter.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/payment/charge_rules.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/payment/stripe_adapter.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity_python.egg-info/dependency_links.txt +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity_python.egg-info/entry_points.txt +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity_python.egg-info/requires.txt +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity_python.egg-info/top_level.txt +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_amplify_build.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_async_support.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_batch_operations.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_concurrency_safety.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_connection_pool.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_connection_resilience.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_decorators.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_email_processing.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_iconv_money_to_cents.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_lambda_handler.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_lambda_handler_auth.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_mixins_import.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_n_plus_one.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_observability.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_payment_braintree_adapter.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_payment_profile_sorting.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_payment_stripe_adapter.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_pdf.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_prepared_statements.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_psycopg3_upgrade.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_query_cache.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_row_batch_update.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_row_cache_staleness.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_row_dirty_tracking.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_schema_migrations.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_security_hardening.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_spreadsheet_functions.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_sqs_per_record_transactions.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_sys_modified_count_postgres_demo.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_table_alter.py +0 -0
- {velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_where_clause_validation.py +0 -0
|
@@ -28,6 +28,16 @@ _LAZY_ATTRS = {
|
|
|
28
28
|
"initialize_build_environment": "velocity.aws.amplify_build",
|
|
29
29
|
"run_backend_deployment": "velocity.aws.amplify_build",
|
|
30
30
|
"update_lambda_layers_to_latest": "velocity.aws.amplify_build",
|
|
31
|
+
# S3 utilities
|
|
32
|
+
"generate_presigned_get": "velocity.aws.s3",
|
|
33
|
+
"generate_presigned_put": "velocity.aws.s3",
|
|
34
|
+
"list_client_files": "velocity.aws.s3",
|
|
35
|
+
"normalize_client_prefix": "velocity.aws.s3",
|
|
36
|
+
"CLIENT_FILES_BUCKET": "velocity.aws.s3",
|
|
37
|
+
"PUBLIC_ASSETS_BUCKET": "velocity.aws.s3",
|
|
38
|
+
"BACKOFFICE_BUCKET": "velocity.aws.s3",
|
|
39
|
+
"PRIVATE_BUCKETS": "velocity.aws.s3",
|
|
40
|
+
"ALLOWED_UPLOAD_BUCKETS": "velocity.aws.s3",
|
|
31
41
|
}
|
|
32
42
|
|
|
33
43
|
|
|
@@ -47,4 +57,14 @@ __all__ = [
|
|
|
47
57
|
"initialize_build_environment",
|
|
48
58
|
"run_backend_deployment",
|
|
49
59
|
"update_lambda_layers_to_latest",
|
|
60
|
+
# S3 utilities
|
|
61
|
+
"generate_presigned_get",
|
|
62
|
+
"generate_presigned_put",
|
|
63
|
+
"list_client_files",
|
|
64
|
+
"normalize_client_prefix",
|
|
65
|
+
"CLIENT_FILES_BUCKET",
|
|
66
|
+
"PUBLIC_ASSETS_BUCKET",
|
|
67
|
+
"BACKOFFICE_BUCKET",
|
|
68
|
+
"PRIVATE_BUCKETS",
|
|
69
|
+
"ALLOWED_UPLOAD_BUCKETS",
|
|
50
70
|
]
|
|
@@ -377,7 +377,7 @@ def set_cloudwatch_logging(
|
|
|
377
377
|
f"arn:aws:lambda:{region}:{account_id}:function:LambdaCloudWatchNotification"
|
|
378
378
|
),
|
|
379
379
|
"filterName": function_name,
|
|
380
|
-
"filterPattern": "?
|
|
380
|
+
"filterPattern": "?error ?exception ?warning ?critical ?ERROR ?EXCEPTION ?WARN ?CRITICAL",
|
|
381
381
|
}
|
|
382
382
|
for _attempt in range(2):
|
|
383
383
|
try:
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"""Centralized S3 utilities: presigned URL generation and private-file listing.
|
|
2
|
+
|
|
3
|
+
Architectural principles enforced here
|
|
4
|
+
---------------------------------------
|
|
5
|
+
* All files in *private* buckets (e.g. ``caringcent.client.files``) MUST be
|
|
6
|
+
stored without a public ACL. Access is granted exclusively through
|
|
7
|
+
time-limited presigned GET URLs generated by this module.
|
|
8
|
+
* Direct browser-to-S3 uploads are supported via presigned PUT URLs so that
|
|
9
|
+
file bytes never pass through Lambda (avoids the 6 MB API Gateway payload
|
|
10
|
+
ceiling and reduces Lambda cost).
|
|
11
|
+
* Public-asset buckets (``donate.resources``, ``backoffice.resources``) remain
|
|
12
|
+
unaffected by this module; they continue to use ``ACL: public-read`` when
|
|
13
|
+
uploaded via ``helpers.upload(public=True)``.
|
|
14
|
+
|
|
15
|
+
Bucket constants
|
|
16
|
+
-----------------
|
|
17
|
+
Import and compare against these rather than hard-coding bucket names in
|
|
18
|
+
Lambda handlers so a rename only needs to happen in one place.
|
|
19
|
+
"""
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import re
|
|
23
|
+
import boto3
|
|
24
|
+
|
|
25
|
+
# ---------------------------------------------------------------------------
|
|
26
|
+
# Bucket name constants
|
|
27
|
+
# ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
CLIENT_FILES_BUCKET: str = "caringcent.client.files"
|
|
30
|
+
"""Private bucket that stores per-client files (billing reports, uploads)."""
|
|
31
|
+
|
|
32
|
+
PUBLIC_ASSETS_BUCKET: str = "donate.resources"
|
|
33
|
+
"""Public bucket for images and form-builder assets embedded in donation forms."""
|
|
34
|
+
|
|
35
|
+
BACKOFFICE_BUCKET: str = "backoffice.resources"
|
|
36
|
+
"""Internal bucket for BackOffice admin assets (help videos, data-load ZIPs)."""
|
|
37
|
+
|
|
38
|
+
# Buckets that must never be served with a public ACL.
|
|
39
|
+
PRIVATE_BUCKETS: frozenset[str] = frozenset({CLIENT_FILES_BUCKET})
|
|
40
|
+
|
|
41
|
+
# Buckets that are permitted as upload destinations from BackOffice.
|
|
42
|
+
ALLOWED_UPLOAD_BUCKETS: frozenset[str] = frozenset(
|
|
43
|
+
{CLIENT_FILES_BUCKET, PUBLIC_ASSETS_BUCKET, BACKOFFICE_BUCKET}
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# ---------------------------------------------------------------------------
|
|
48
|
+
# Presigned URL helpers
|
|
49
|
+
# ---------------------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
def generate_presigned_get(
|
|
52
|
+
bucket: str,
|
|
53
|
+
key: str,
|
|
54
|
+
*,
|
|
55
|
+
expires_in: int = 3600,
|
|
56
|
+
filename: str | None = None,
|
|
57
|
+
content_type: str | None = None,
|
|
58
|
+
) -> str:
|
|
59
|
+
"""Return a presigned GET URL for a private S3 object.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
bucket: S3 bucket name.
|
|
63
|
+
key: S3 object key.
|
|
64
|
+
expires_in: URL lifetime in seconds (default 1 hour).
|
|
65
|
+
filename: When provided the presigned URL includes a
|
|
66
|
+
``Content-Disposition: attachment; filename="..."`` override so the
|
|
67
|
+
browser downloads the file under *filename* instead of navigating
|
|
68
|
+
to the raw key. This also prevents the browser from navigating
|
|
69
|
+
away from the current SPA page.
|
|
70
|
+
content_type: Optional ``Content-Type`` override embedded in the
|
|
71
|
+
presigned URL query-string.
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
A time-limited, signed HTTPS URL that grants GET access to the object.
|
|
75
|
+
"""
|
|
76
|
+
params: dict = {"Bucket": bucket, "Key": key}
|
|
77
|
+
if filename:
|
|
78
|
+
params["ResponseContentDisposition"] = f'attachment; filename="{filename}"'
|
|
79
|
+
if content_type:
|
|
80
|
+
params["ResponseContentType"] = content_type
|
|
81
|
+
s3 = boto3.client("s3")
|
|
82
|
+
return s3.generate_presigned_url("get_object", Params=params, ExpiresIn=expires_in)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def generate_presigned_put(
|
|
86
|
+
bucket: str,
|
|
87
|
+
key: str,
|
|
88
|
+
*,
|
|
89
|
+
content_type: str | None = None,
|
|
90
|
+
expires_in: int = 900,
|
|
91
|
+
) -> dict:
|
|
92
|
+
"""Return a presigned PUT URL for a direct browser-to-S3 upload.
|
|
93
|
+
|
|
94
|
+
Using this URL the browser PUTs the file body directly to S3, bypassing
|
|
95
|
+
Lambda entirely. This removes the 6 MB API Gateway payload limit and
|
|
96
|
+
reduces Lambda invocation cost for large files.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
bucket: S3 bucket name.
|
|
100
|
+
key: S3 object key for the uploaded file.
|
|
101
|
+
content_type: Optional MIME type. When supplied the client **must**
|
|
102
|
+
send the same ``Content-Type`` header in the PUT request, otherwise
|
|
103
|
+
S3 rejects the upload with a 403.
|
|
104
|
+
expires_in: URL lifetime in seconds (default 15 minutes).
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
dict with keys ``url`` (the presigned PUT URL), ``key``, and
|
|
108
|
+
``bucket``. Pass this dict back to the frontend; the browser calls
|
|
109
|
+
``fetch(url, { method: 'PUT', body: file })`` to upload.
|
|
110
|
+
"""
|
|
111
|
+
params: dict = {"Bucket": bucket, "Key": key}
|
|
112
|
+
if content_type:
|
|
113
|
+
params["ContentType"] = content_type
|
|
114
|
+
s3 = boto3.client("s3")
|
|
115
|
+
url = s3.generate_presigned_url("put_object", Params=params, ExpiresIn=expires_in)
|
|
116
|
+
return {"url": url, "key": key, "bucket": bucket}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
# ---------------------------------------------------------------------------
|
|
120
|
+
# Object listing helpers
|
|
121
|
+
# ---------------------------------------------------------------------------
|
|
122
|
+
|
|
123
|
+
def normalize_client_prefix(client_id: str) -> str:
|
|
124
|
+
"""Normalise *client_id* to the S3 key prefix used when storing files.
|
|
125
|
+
|
|
126
|
+
The convention (established by ``OnActionAdminUploadFiles``) is
|
|
127
|
+
``lowercase + spaces → hyphens``, matching the existing
|
|
128
|
+
``client_id.lower().replace(" ", "-")`` pattern.
|
|
129
|
+
"""
|
|
130
|
+
return re.sub(r"\s+", "-", (client_id or "").strip().lower())
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def list_client_files(
|
|
134
|
+
bucket: str,
|
|
135
|
+
client_prefix: str,
|
|
136
|
+
*,
|
|
137
|
+
expires_in: int = 3600,
|
|
138
|
+
) -> list[dict]:
|
|
139
|
+
"""List non-empty objects under *client_prefix* and attach presigned URLs.
|
|
140
|
+
|
|
141
|
+
Zero-byte objects (S3 directory markers created by the console) are
|
|
142
|
+
silently skipped.
|
|
143
|
+
|
|
144
|
+
Each returned dict is the original S3 ``Contents`` entry enriched with:
|
|
145
|
+
|
|
146
|
+
* ``SignedUrl`` – presigned GET URL valid for *expires_in* seconds.
|
|
147
|
+
* ``Header`` – humanized sub-folder name (second-to-last key component),
|
|
148
|
+
used as the category label in :class:`S3DownloadsList`.
|
|
149
|
+
* ``FileName`` – the bare filename (last key component).
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
bucket: S3 bucket name.
|
|
153
|
+
client_prefix: Key prefix, typically the normalized client ID.
|
|
154
|
+
expires_in: Presigned URL lifetime in seconds (default 1 hour).
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
List of enriched object dicts, empty if the prefix has no objects.
|
|
158
|
+
"""
|
|
159
|
+
s3 = boto3.client("s3")
|
|
160
|
+
result = s3.list_objects_v2(Bucket=bucket, Prefix=client_prefix, MaxKeys=100)
|
|
161
|
+
enriched: list[dict] = []
|
|
162
|
+
for obj in result.get("Contents", []):
|
|
163
|
+
if obj.get("Size", 0) == 0:
|
|
164
|
+
continue # skip directory-marker objects
|
|
165
|
+
key: str = obj["Key"]
|
|
166
|
+
parts = key.split("/")
|
|
167
|
+
obj["SignedUrl"] = generate_presigned_get(bucket, key, expires_in=expires_in)
|
|
168
|
+
obj["Header"] = (
|
|
169
|
+
parts[-2].replace("_", " ").replace("-", " ").title()
|
|
170
|
+
if len(parts) > 1
|
|
171
|
+
else ""
|
|
172
|
+
)
|
|
173
|
+
obj["FileName"] = parts[-1]
|
|
174
|
+
enriched.append(obj)
|
|
175
|
+
return enriched
|
|
@@ -6,6 +6,7 @@ src/velocity/logging.py
|
|
|
6
6
|
src/velocity/aws/__init__.py
|
|
7
7
|
src/velocity/aws/amplify.py
|
|
8
8
|
src/velocity/aws/amplify_build.py
|
|
9
|
+
src/velocity/aws/s3.py
|
|
9
10
|
src/velocity/aws/handlers/__init__.py
|
|
10
11
|
src/velocity/aws/handlers/base_handler.py
|
|
11
12
|
src/velocity/aws/handlers/context.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/handlers/context_factory.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/handlers/lambda_handler.py
RENAMED
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/handlers/mixins/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/handlers/mixins/data_service.py
RENAMED
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/aws/handlers/mixins/web_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/base/initializer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/mysql/operators.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/postgres/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/postgres/operators.py
RENAMED
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/postgres/reserved.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/sqlite/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/sqlite/operators.py
RENAMED
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/sqlite/reserved.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/sqlserver/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/sqlserver/operators.py
RENAMED
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/sqlserver/reserved.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/servers/sqlserver/types.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_column.py
RENAMED
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_connections.py
RENAMED
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_database.py
RENAMED
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_engine.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_imports.py
RENAMED
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_result.py
RENAMED
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_row.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_sequence.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_table.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/postgres/test_transaction.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/test_cursor_rowcount_fix.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/test_postgres_unchanged.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/test_result_caching.py
RENAMED
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/db/tests/test_result_sql_aware.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/misc/tests/test_original_error.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity/payment/authorizenet_adapter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity_python.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity_python.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/src/velocity_python.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.20 → velocity_python-0.1.22}/tests/test_sys_modified_count_postgres_demo.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|