From a71b53b578b3e14648d38e1c16736b5f5f3422d1 Mon Sep 17 00:00:00 2001 From: alvseven Date: Sat, 18 Apr 2026 13:12:01 -0300 Subject: [PATCH] fix: restore TOS endpoints Re-add Terms of Service resource files that were removed in a833f53. Wire TOS into client classes and instance namespaces. Bump version to 2.1.0. --- pyproject.toml | 2 +- src/blindpay/__init__.py | 2 +- src/blindpay/client.py | 28 +++++++ src/blindpay/resources/__init__.py | 3 + .../resources/terms_of_service/__init__.py | 17 +++++ .../terms_of_service/terms_of_service.py | 42 +++++++++++ tests/resources/test_terms_of_service.py | 74 +++++++++++++++++++ 7 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 src/blindpay/resources/terms_of_service/__init__.py create mode 100644 src/blindpay/resources/terms_of_service/terms_of_service.py create mode 100644 tests/resources/test_terms_of_service.py diff --git a/pyproject.toml b/pyproject.toml index 54b8da5..255444a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "blindpay" -version = "2.0.1" +version = "2.1.0" description = "Official Python SDK for the Blindpay API — Global payments infrastructure" readme = "README.md" authors = [{ name = "Blindpay", email = "alves@blindpay.com" }] diff --git a/src/blindpay/__init__.py b/src/blindpay/__init__.py index 3c684b6..538888a 100644 --- a/src/blindpay/__init__.py +++ b/src/blindpay/__init__.py @@ -1,4 +1,4 @@ -__version__ = "2.0.1" +__version__ = "2.1.0" from ._internal.exceptions import BlindPayError from .client import BlindPay, BlindPaySync diff --git a/src/blindpay/client.py b/src/blindpay/client.py index 26c861d..0fb9d3b 100644 --- a/src/blindpay/client.py +++ b/src/blindpay/client.py @@ -25,6 +25,10 @@ from blindpay.resources.payouts.payouts import PayoutsResource, PayoutsResourceSync from blindpay.resources.quotes.quotes import QuotesResource, QuotesResourceSync from blindpay.resources.receivers.receivers import ReceiversResource, ReceiversResourceSync + from blindpay.resources.terms_of_service.terms_of_service import ( + TermsOfServiceResource, + TermsOfServiceResourceSync, + ) from blindpay.resources.transfers.transfers import TransfersResource, TransfersResourceSync from blindpay.resources.upload.upload import UploadResource, UploadResourceSync from blindpay.resources.virtual_accounts.virtual_accounts import ( @@ -168,6 +172,12 @@ def webhook_endpoints(self) -> "WebhookEndpointsResource": return create_webhook_endpoints_resource(self._instance_id, self._api) + @cached_property + def terms_of_service(self) -> "TermsOfServiceResource": + from blindpay.resources.terms_of_service import create_terms_of_service_resource + + return create_terms_of_service_resource(self._instance_id, self._api) + def __getattr__(self, name: str) -> Any: return getattr(self._base, name) @@ -327,6 +337,12 @@ def upload(self) -> "UploadResource": return create_upload_resource(self._api) + @cached_property + def terms_of_service(self) -> "TermsOfServiceResource": + from blindpay.resources.terms_of_service import create_terms_of_service_resource + + return create_terms_of_service_resource(self._instance_id, self._api) + def verify_webhook_signature( self, *, secret: str, id: str, timestamp: str, payload: str, svix_signature: str ) -> bool: @@ -386,6 +402,12 @@ def webhook_endpoints(self) -> "WebhookEndpointsResourceSync": return create_webhook_endpoints_resource_sync(self._instance_id, self._api) + @cached_property + def terms_of_service(self) -> "TermsOfServiceResourceSync": + from blindpay.resources.terms_of_service import create_terms_of_service_resource_sync + + return create_terms_of_service_resource_sync(self._instance_id, self._api) + def __getattr__(self, name: str) -> Any: return getattr(self._base, name) @@ -545,6 +567,12 @@ def upload(self) -> "UploadResourceSync": return create_upload_resource_sync(self._api) + @cached_property + def terms_of_service(self) -> "TermsOfServiceResourceSync": + from blindpay.resources.terms_of_service import create_terms_of_service_resource_sync + + return create_terms_of_service_resource_sync(self._instance_id, self._api) + def verify_webhook_signature( self, *, secret: str, id: str, timestamp: str, payload: str, svix_signature: str ) -> bool: diff --git a/src/blindpay/resources/__init__.py b/src/blindpay/resources/__init__.py index 4b553f9..3819881 100644 --- a/src/blindpay/resources/__init__.py +++ b/src/blindpay/resources/__init__.py @@ -9,6 +9,7 @@ from .payouts import create_payouts_resource from .quotes import create_quotes_resource from .receivers import create_receivers_resource +from .terms_of_service import create_terms_of_service_resource, create_terms_of_service_resource_sync from .transfers import create_transfers_resource from .upload import create_upload_resource from .virtual_accounts import create_virtual_accounts_resource @@ -28,6 +29,8 @@ "create_payouts_resource", "create_quotes_resource", "create_receivers_resource", + "create_terms_of_service_resource", + "create_terms_of_service_resource_sync", "create_transfers_resource", "create_upload_resource", "create_virtual_accounts_resource", diff --git a/src/blindpay/resources/terms_of_service/__init__.py b/src/blindpay/resources/terms_of_service/__init__.py new file mode 100644 index 0000000..aabbaa8 --- /dev/null +++ b/src/blindpay/resources/terms_of_service/__init__.py @@ -0,0 +1,17 @@ +from .terms_of_service import ( + InitiateInput, + InitiateResponse, + TermsOfServiceResource, + TermsOfServiceResourceSync, + create_terms_of_service_resource, + create_terms_of_service_resource_sync, +) + +__all__ = [ + "create_terms_of_service_resource", + "create_terms_of_service_resource_sync", + "TermsOfServiceResource", + "TermsOfServiceResourceSync", + "InitiateInput", + "InitiateResponse", +] diff --git a/src/blindpay/resources/terms_of_service/terms_of_service.py b/src/blindpay/resources/terms_of_service/terms_of_service.py new file mode 100644 index 0000000..47057d8 --- /dev/null +++ b/src/blindpay/resources/terms_of_service/terms_of_service.py @@ -0,0 +1,42 @@ +from typing_extensions import Optional, TypedDict + +from ..._internal.api_client import InternalApiClient, InternalApiClientSync +from ...types import BlindpayApiResponse + + +class InitiateInput(TypedDict): + idempotency_key: str + receiver_id: Optional[str] + redirect_url: Optional[str] + + +class InitiateResponse(TypedDict): + url: str + + +class TermsOfServiceResource: + def __init__(self, instance_id: str, client: InternalApiClient): + self._instance_id = instance_id + self._client = client + + async def initiate(self, data: InitiateInput) -> BlindpayApiResponse[InitiateResponse]: + return await self._client.post(f"/e/instances/{self._instance_id}/tos", data) + + +class TermsOfServiceResourceSync: + def __init__(self, instance_id: str, client: InternalApiClientSync): + self._instance_id = instance_id + self._client = client + + def initiate(self, data: InitiateInput) -> BlindpayApiResponse[InitiateResponse]: + return self._client.post(f"/e/instances/{self._instance_id}/tos", data) + + +def create_terms_of_service_resource(instance_id: str, client: InternalApiClient) -> TermsOfServiceResource: + return TermsOfServiceResource(instance_id, client) + + +def create_terms_of_service_resource_sync( + instance_id: str, client: InternalApiClientSync +) -> TermsOfServiceResourceSync: + return TermsOfServiceResourceSync(instance_id, client) diff --git a/tests/resources/test_terms_of_service.py b/tests/resources/test_terms_of_service.py new file mode 100644 index 0000000..eb84db7 --- /dev/null +++ b/tests/resources/test_terms_of_service.py @@ -0,0 +1,74 @@ +from unittest.mock import patch + +import pytest + +from blindpay import BlindPay, BlindPaySync + + +class TestTermsOfService: + @pytest.fixture(autouse=True) + def setup(self): + self.blindpay = BlindPay(api_key="test-key", instance_id="in_000000000000") + + @pytest.mark.asyncio + async def test_initiate_terms_of_service(self): + mocked_url = { + "url": "https://app.blindpay.com/e/terms-of-service?session_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", + } + + with patch.object(self.blindpay._api, "_request") as mock_request: + mock_request.return_value = {"data": mocked_url, "error": None} + + response = await self.blindpay.instances.terms_of_service.initiate( + { + "idempotency_key": "123e4567-e89b-12d3-a456-426614174000", + "receiver_id": None, + "redirect_url": None, + } + ) + + assert response["error"] is None + assert response["data"] == mocked_url + mock_request.assert_called_once_with( + "POST", + "/e/instances/in_000000000000/tos", + { + "idempotency_key": "123e4567-e89b-12d3-a456-426614174000", + "receiver_id": None, + "redirect_url": None, + }, + ) + + +class TestTermsOfServiceSync: + @pytest.fixture(autouse=True) + def setup(self): + self.blindpay = BlindPaySync(api_key="test-key", instance_id="in_000000000000") + + def test_initiate_terms_of_service(self): + mocked_url = { + "url": "https://app.blindpay.com/e/terms-of-service?session_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", + } + + with patch.object(self.blindpay._api, "_request") as mock_request: + mock_request.return_value = {"data": mocked_url, "error": None} + + response = self.blindpay.instances.terms_of_service.initiate( + { + "idempotency_key": "123e4567-e89b-12d3-a456-426614174000", + "receiver_id": None, + "redirect_url": None, + } + ) + + assert response["error"] is None + assert response["data"] == mocked_url + mock_request.assert_called_once_with( + "POST", + "/e/instances/in_000000000000/tos", + { + "idempotency_key": "123e4567-e89b-12d3-a456-426614174000", + "receiver_id": None, + "redirect_url": None, + }, + )