From 2ce97343ee676a163b383b8040737ac481dfbb03 Mon Sep 17 00:00:00 2001 From: ilfa Date: Wed, 5 Feb 2025 11:41:25 +0000 Subject: [PATCH 1/7] feat: update OpenAPI schema --- .changeset/forty-seas-prove.md | 5 + .changeset/good-experts-watch.md | 5 + .changeset/orange-poets-drive.md | 5 + .changeset/pre.json | 8 + README.md | 3 + docs/FingerprintApi.md | 67 ++++++++ docs/SearchEventsResponse.md | 12 ++ docs/SearchEventsResponseEvents.md | 11 ++ fingerprint_pro_server_api_sdk/__init__.py | 2 + .../api/fingerprint_api.py | 145 ++++++++++++++++++ .../models/__init__.py | 2 + .../models/search_events_response.py | 96 ++++++++++++ .../models/search_events_response_events.py | 72 +++++++++ res/fingerprint-server-api.yaml | 144 +++++++++++++++++ 14 files changed, 577 insertions(+) create mode 100644 .changeset/forty-seas-prove.md create mode 100644 .changeset/good-experts-watch.md create mode 100644 .changeset/orange-poets-drive.md create mode 100644 .changeset/pre.json create mode 100644 docs/SearchEventsResponse.md create mode 100644 docs/SearchEventsResponseEvents.md create mode 100644 fingerprint_pro_server_api_sdk/models/search_events_response.py create mode 100644 fingerprint_pro_server_api_sdk/models/search_events_response_events.py diff --git a/.changeset/forty-seas-prove.md b/.changeset/forty-seas-prove.md new file mode 100644 index 00000000..b2e8f0e8 --- /dev/null +++ b/.changeset/forty-seas-prove.md @@ -0,0 +1,5 @@ +--- +'fingerprint-pro-server-api-python-sdk': minor +--- + +Add `relay` detection method to the VPN Detection Smart Signal diff --git a/.changeset/good-experts-watch.md b/.changeset/good-experts-watch.md new file mode 100644 index 00000000..e707a1f5 --- /dev/null +++ b/.changeset/good-experts-watch.md @@ -0,0 +1,5 @@ +--- +'fingerprint-pro-server-api-python-sdk': minor +--- + +**events-search**: Add a new `events/search` API endpoint. Allow users to search for identification events matching one or more search criteria, for example, visitor ID, IP address, bot detection result, etc. diff --git a/.changeset/orange-poets-drive.md b/.changeset/orange-poets-drive.md new file mode 100644 index 00000000..0c1a1fd8 --- /dev/null +++ b/.changeset/orange-poets-drive.md @@ -0,0 +1,5 @@ +--- +'fingerprint-pro-server-api-python-sdk': minor +--- + +**events**: Add a `suspect` field to the `identification` product schema \ No newline at end of file diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 00000000..97aacec0 --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,8 @@ +{ + "mode": "pre", + "tag": "rc", + "initialVersions": { + "fingerprint-pro-server-api-python-sdk": "8.2.1" + }, + "changesets": [] +} diff --git a/README.md b/README.md index 8f5bd424..97dad6e9 100644 --- a/README.md +++ b/README.md @@ -256,6 +256,7 @@ Class | Method | HTTP request | Description *FingerprintApi* | [**get_event**](docs/FingerprintApi.md#get_event) | **GET** /events/{request_id} | Get event by request ID *FingerprintApi* | [**get_related_visitors**](docs/FingerprintApi.md#get_related_visitors) | **GET** /related-visitors | Get Related Visitors *FingerprintApi* | [**get_visits**](docs/FingerprintApi.md#get_visits) | **GET** /visitors/{visitor_id} | Get visits by visitor ID +*FingerprintApi* | [**search_events**](docs/FingerprintApi.md#search_events) | **GET** /events/search | Get events via search *FingerprintApi* | [**update_event**](docs/FingerprintApi.md#update_event) | **PUT** /events/{request_id} | Update an event with a given request ID ## Documentation For Models @@ -330,6 +331,8 @@ Class | Method | HTTP request | Description - [RelatedVisitorsResponse](docs/RelatedVisitorsResponse.md) - [RemoteControl](docs/RemoteControl.md) - [RootApps](docs/RootApps.md) + - [SearchEventsResponse](docs/SearchEventsResponse.md) + - [SearchEventsResponseEvents](docs/SearchEventsResponseEvents.md) - [SuspectScore](docs/SuspectScore.md) - [Tag](docs/Tag.md) - [Tampering](docs/Tampering.md) diff --git a/docs/FingerprintApi.md b/docs/FingerprintApi.md index 283ea44b..7be00f20 100644 --- a/docs/FingerprintApi.md +++ b/docs/FingerprintApi.md @@ -8,6 +8,7 @@ Method | HTTP request | Description [**get_event**](FingerprintApi.md#get_event) | **GET** /events/{request_id} | Get event by request ID [**get_related_visitors**](FingerprintApi.md#get_related_visitors) | **GET** /related-visitors | Get Related Visitors [**get_visits**](FingerprintApi.md#get_visits) | **GET** /visitors/{visitor_id} | Get visits by visitor ID +[**search_events**](FingerprintApi.md#search_events) | **GET** /events/search | Get events via search [**update_event**](FingerprintApi.md#update_event) | **PUT** /events/{request_id} | Update an event with a given request ID # **delete_visitor_data** @@ -219,6 +220,72 @@ Name | Type | Description | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +# **search_events** +> SearchEventsResponse search_events(limit, visitor_id=visitor_id, bot=bot, ip_address=ip_address, linked_id=linked_id, start=start, end=end, reverse=reverse, suspect=suspect) + +Get events via search + +Search for identification events, including Smart Signals, using multiple filtering criteria. If you don't provide `start` or `end` parameters, the default search range is the last 7 days. Please note that events include mobile signals (e.g. `rootApps`) even if the request originated from a non-mobile platform. We recommend you **ignore** mobile signals for such requests. + +### Example +```python +import fingerprint_pro_server_api_sdk +from fingerprint_pro_server_api_sdk.rest import ApiException + +# Configure API key authorization and region +configuration = fingerprint_pro_server_api_sdk.Configuration(api_key="SECRET_API_KEY") +# configuration = fingerprint_pro_server_api_sdk.Configuration(api_key="SECRET_API_KEY", region="eu") + +# create an instance of the API class +api_instance = fingerprint_pro_server_api_sdk.FingerprintApi(configuration) + +limit = 56 # int | Limit the number of events returned. +visitor_id = 'visitor_id_example' # str | Unique [visitor identifier](https://dev.fingerprint.com/reference/get-function#visitorid) issued by Fingerprint Pro. Filter for events matching this `visitor_id`. (optional) +bot = 'bot_example' # str | Filter events by the bot detection result, specifically: - events where any kind of bot was detected. - events where a good bot was detected. - events where a bad bot was detected. - events where no bot was detected. (optional) +ip_address = 'ip_address_example' # str | Filter events by IP address range. The range can be as specific as a single IP (/32 for IPv4 or /128 for IPv6) All ip_address filters must use CIDR notation, for example, 10.0.0.0/24, 192.168.0.1/32 (optional) +linked_id = 'linked_id_example' # str | Filter events by your custom identifier. You can use [linked IDs](https://dev.fingerprint.com/reference/get-function#linkedid) to associate identification requests with your own identifier, for example, session ID, purchase ID, or transaction ID. You can then use this `linked_id` parameter to retrieve all events associated with your custom identifier. (optional) +start = 789 # int | Filter events with a timestamp greater than the start time, in Unix time (milliseconds). (optional) +end = 789 # int | Filter events with a timestamp smaller than the end time, in Unix time (milliseconds). (optional) +reverse = true # bool | Sort events in reverse timestamp order. (optional) +suspect = true # bool | Filter events previously tagged as suspicious via the [Update API](https://dev.fingerprint.com/reference/updateevent). (optional) + +try: + # Get events via search + api_response = api_instance.search_events(limit, visitor_id=visitor_id, bot=bot, ip_address=ip_address, linked_id=linked_id, start=start, end=end, reverse=reverse, suspect=suspect) + print(api_response) +except ApiException as e: + print("Exception when calling FingerprintApi->search_events: %s\n" % e) +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **limit** | **int**| Limit the number of events returned. | + **visitor_id** | **str**| Unique [visitor identifier](https://dev.fingerprint.com/reference/get-function#visitorid) issued by Fingerprint Pro. Filter for events matching this `visitor_id`. | [optional] + **bot** | **str**| Filter events by the bot detection result, specifically: - events where any kind of bot was detected. - events where a good bot was detected. - events where a bad bot was detected. - events where no bot was detected. | [optional] + **ip_address** | **str**| Filter events by IP address range. The range can be as specific as a single IP (/32 for IPv4 or /128 for IPv6) All ip_address filters must use CIDR notation, for example, 10.0.0.0/24, 192.168.0.1/32 | [optional] + **linked_id** | **str**| Filter events by your custom identifier. You can use [linked IDs](https://dev.fingerprint.com/reference/get-function#linkedid) to associate identification requests with your own identifier, for example, session ID, purchase ID, or transaction ID. You can then use this `linked_id` parameter to retrieve all events associated with your custom identifier. | [optional] + **start** | **int**| Filter events with a timestamp greater than the start time, in Unix time (milliseconds). | [optional] + **end** | **int**| Filter events with a timestamp smaller than the end time, in Unix time (milliseconds). | [optional] + **reverse** | **bool**| Sort events in reverse timestamp order. | [optional] + **suspect** | **bool**| Filter events previously tagged as suspicious via the [Update API](https://dev.fingerprint.com/reference/updateevent). | [optional] + +### Return type + +[**SearchEventsResponse**](SearchEventsResponse.md) + +### Authorization + +[ApiKeyHeader](../README.md#ApiKeyHeader), [ApiKeyQuery](../README.md#ApiKeyQuery) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + # **update_event** > update_event(body, request_id) diff --git a/docs/SearchEventsResponse.md b/docs/SearchEventsResponse.md new file mode 100644 index 00000000..552c91d1 --- /dev/null +++ b/docs/SearchEventsResponse.md @@ -0,0 +1,12 @@ +# SearchEventsResponse +Contains a list of all identification events matching the specified search criteria. + + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**events** | [**list[SearchEventsResponseEvents]**](SearchEventsResponseEvents.md) | | [optional] +**pagination_key** | **str** | | [optional] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/docs/SearchEventsResponseEvents.md b/docs/SearchEventsResponseEvents.md new file mode 100644 index 00000000..410d5188 --- /dev/null +++ b/docs/SearchEventsResponseEvents.md @@ -0,0 +1,11 @@ +# SearchEventsResponseEvents +Device intelligence results for the identification event. + + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**products** | [**Products**](Products.md) | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + diff --git a/fingerprint_pro_server_api_sdk/__init__.py b/fingerprint_pro_server_api_sdk/__init__.py index 511e4238..baaa97f3 100644 --- a/fingerprint_pro_server_api_sdk/__init__.py +++ b/fingerprint_pro_server_api_sdk/__init__.py @@ -90,6 +90,8 @@ from fingerprint_pro_server_api_sdk.models.related_visitors_response import RelatedVisitorsResponse from fingerprint_pro_server_api_sdk.models.remote_control import RemoteControl from fingerprint_pro_server_api_sdk.models.root_apps import RootApps +from fingerprint_pro_server_api_sdk.models.search_events_response import SearchEventsResponse +from fingerprint_pro_server_api_sdk.models.search_events_response_events import SearchEventsResponseEvents from fingerprint_pro_server_api_sdk.models.suspect_score import SuspectScore from fingerprint_pro_server_api_sdk.models.tag import Tag from fingerprint_pro_server_api_sdk.models.tampering import Tampering diff --git a/fingerprint_pro_server_api_sdk/api/fingerprint_api.py b/fingerprint_pro_server_api_sdk/api/fingerprint_api.py index 8070cea4..ca686f89 100644 --- a/fingerprint_pro_server_api_sdk/api/fingerprint_api.py +++ b/fingerprint_pro_server_api_sdk/api/fingerprint_api.py @@ -24,6 +24,7 @@ from fingerprint_pro_server_api_sdk.models.events_get_response import EventsGetResponse # noqa: F401 from fingerprint_pro_server_api_sdk.models.events_update_request import EventsUpdateRequest # noqa: F401 from fingerprint_pro_server_api_sdk.models.related_visitors_response import RelatedVisitorsResponse # noqa: F401 +from fingerprint_pro_server_api_sdk.models.search_events_response import SearchEventsResponse # noqa: F401 from fingerprint_pro_server_api_sdk.models.visitors_get_response import VisitorsGetResponse # noqa: F401 @@ -495,6 +496,150 @@ def get_visits_with_http_info(self, visitor_id: str, **kwargs): # noqa: E501 raise extend_exception(e, error) raise e + def search_events(self, limit: int, **kwargs) -> Union[SearchEventsResponse, AsyncResult[SearchEventsResponse]]: # noqa: E501 + """Get events via search # noqa: E501 + + Search for identification events, including Smart Signals, using multiple filtering criteria. If you don't provide `start` or `end` parameters, the default search range is the last 7 days. Please note that events include mobile signals (e.g. `rootApps`) even if the request originated from a non-mobile platform. We recommend you **ignore** mobile signals for such requests. # noqa: E501 + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + >>> thread = api.search_events(limit, async_req=True) + >>> result = thread.get() + + :param async_req bool + :param limit: Limit the number of events returned. (required) + :param visitor_id: Unique [visitor identifier](https://dev.fingerprint.com/reference/get-function#visitorid) issued by Fingerprint Pro. Filter for events matching this `visitor_id`. + :param bot: Filter events by the bot detection result, specifically: - events where any kind of bot was detected. - events where a good bot was detected. - events where a bad bot was detected. - events where no bot was detected. + :param ip_address: Filter events by IP address range. The range can be as specific as a single IP (/32 for IPv4 or /128 for IPv6) All ip_address filters must use CIDR notation, for example, 10.0.0.0/24, 192.168.0.1/32 + :param linked_id: Filter events by your custom identifier. You can use [linked IDs](https://dev.fingerprint.com/reference/get-function#linkedid) to associate identification requests with your own identifier, for example, session ID, purchase ID, or transaction ID. You can then use this `linked_id` parameter to retrieve all events associated with your custom identifier. + :param start: Filter events with a timestamp greater than the start time, in Unix time (milliseconds). + :param end: Filter events with a timestamp smaller than the end time, in Unix time (milliseconds). + :param reverse: Sort events in reverse timestamp order. + :param suspect: Filter events previously tagged as suspicious via the [Update API](https://dev.fingerprint.com/reference/updateevent). + :return: SearchEventsResponse + If the method is called asynchronously, + returns the request thread. + """ + kwargs['_return_http_data_only'] = True + if kwargs.get('async_req'): + return self.search_events_with_http_info(limit, **kwargs) # noqa: E501 + else: + (data) = self.search_events_with_http_info(limit, **kwargs) # noqa: E501 + return data + + def search_events_with_http_info(self, limit: int, **kwargs): # noqa: E501 + """Get events via search # noqa: E501 + + Search for identification events, including Smart Signals, using multiple filtering criteria. If you don't provide `start` or `end` parameters, the default search range is the last 7 days. Please note that events include mobile signals (e.g. `rootApps`) even if the request originated from a non-mobile platform. We recommend you **ignore** mobile signals for such requests. # noqa: E501 + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + >>> thread = api.search_events_with_http_info(limit, async_req=True) + >>> result = thread.get() + + :param async_req bool + :param int limit: Limit the number of events returned. (required) + :param str visitor_id: Unique [visitor identifier](https://dev.fingerprint.com/reference/get-function#visitorid) issued by Fingerprint Pro. Filter for events matching this `visitor_id`. + :param str bot: Filter events by the bot detection result, specifically: - events where any kind of bot was detected. - events where a good bot was detected. - events where a bad bot was detected. - events where no bot was detected. + :param str ip_address: Filter events by IP address range. The range can be as specific as a single IP (/32 for IPv4 or /128 for IPv6) All ip_address filters must use CIDR notation, for example, 10.0.0.0/24, 192.168.0.1/32 + :param str linked_id: Filter events by your custom identifier. You can use [linked IDs](https://dev.fingerprint.com/reference/get-function#linkedid) to associate identification requests with your own identifier, for example, session ID, purchase ID, or transaction ID. You can then use this `linked_id` parameter to retrieve all events associated with your custom identifier. + :param int start: Filter events with a timestamp greater than the start time, in Unix time (milliseconds). + :param int end: Filter events with a timestamp smaller than the end time, in Unix time (milliseconds). + :param bool reverse: Sort events in reverse timestamp order. + :param bool suspect: Filter events previously tagged as suspicious via the [Update API](https://dev.fingerprint.com/reference/updateevent). + :return: SearchEventsResponse + If the method is called asynchronously, + returns the request thread. + """ + + all_params = [ + 'limit', + 'visitor_id', + 'bot', + 'ip_address', + 'linked_id', + 'start', + 'end', + 'reverse', + 'suspect', + 'async_req', + '_return_http_data_only', + '_preload_content', + '_request_timeout'] + + params = locals() + for key, val in params['kwargs'].items(): + if key not in all_params: + raise TypeError( + "Got an unexpected keyword argument '%s'" + " to method search_events" % key + ) + params[key] = val + del params['kwargs'] + # verify the required parameter 'limit' is set + if 'limit' not in params or params['limit'] is None: + raise ValueError("Missing the required parameter `limit` when calling `search_events`") # noqa: E501 + + collection_formats = {} + + path_params = {} + + query_params = [('ii', 'fingerprint-pro-server-python-sdk/8.2.1')] + if 'limit' in params: + query_params.append(('limit', params['limit'])) # noqa: E501 + if 'visitor_id' in params: + query_params.append(('visitor_id', params['visitor_id'])) # noqa: E501 + if 'bot' in params: + query_params.append(('bot', params['bot'])) # noqa: E501 + if 'ip_address' in params: + query_params.append(('ip_address', params['ip_address'])) # noqa: E501 + if 'linked_id' in params: + query_params.append(('linked_id', params['linked_id'])) # noqa: E501 + if 'start' in params: + query_params.append(('start', params['start'])) # noqa: E501 + if 'end' in params: + query_params.append(('end', params['end'])) # noqa: E501 + if 'reverse' in params: + query_params.append(('reverse', params['reverse'])) # noqa: E501 + if 'suspect' in params: + query_params.append(('suspect', params['suspect'])) # noqa: E501 + + header_params = {} + + form_params = [] + local_var_files = {} + + body_params = None + # HTTP header `Accept` + header_params['Accept'] = self.api_client.select_header_accept( + ['application/json']) # noqa: E501 + + # Authentication setting + auth_settings = ['ApiKeyHeader', 'ApiKeyQuery'] # noqa: E501 + + try: + return self.api_client.call_api( + '/events/search', 'GET', + path_params, + query_params, + header_params, + body=body_params, + post_params=form_params, + files=local_var_files, + response_type='SearchEventsResponse', # noqa: E501 + auth_settings=auth_settings, + async_req=params.get('async_req'), + _return_http_data_only=params.get('_return_http_data_only'), + _preload_content=params.get('_preload_content', True), + _request_timeout=params.get('_request_timeout'), + collection_formats=collection_formats) + except ApiException as e: + if e.status == 400: + error = self.api_client.deserialize(e, 'ErrorResponse', True) + raise extend_exception(e, error) + if e.status == 403: + error = self.api_client.deserialize(e, 'ErrorResponse', True) + raise extend_exception(e, error) + raise e + def update_event(self, body: EventsUpdateRequest, request_id: str, **kwargs) -> Union[None, AsyncResult[None]]: # noqa: E501 """Update an event with a given request ID # noqa: E501 diff --git a/fingerprint_pro_server_api_sdk/models/__init__.py b/fingerprint_pro_server_api_sdk/models/__init__.py index a0eb8fcc..c6c22b4f 100644 --- a/fingerprint_pro_server_api_sdk/models/__init__.py +++ b/fingerprint_pro_server_api_sdk/models/__init__.py @@ -82,6 +82,8 @@ from fingerprint_pro_server_api_sdk.models.related_visitors_response import RelatedVisitorsResponse from fingerprint_pro_server_api_sdk.models.remote_control import RemoteControl from fingerprint_pro_server_api_sdk.models.root_apps import RootApps +from fingerprint_pro_server_api_sdk.models.search_events_response import SearchEventsResponse +from fingerprint_pro_server_api_sdk.models.search_events_response_events import SearchEventsResponseEvents from fingerprint_pro_server_api_sdk.models.suspect_score import SuspectScore from fingerprint_pro_server_api_sdk.models.tag import Tag from fingerprint_pro_server_api_sdk.models.tampering import Tampering diff --git a/fingerprint_pro_server_api_sdk/models/search_events_response.py b/fingerprint_pro_server_api_sdk/models/search_events_response.py new file mode 100644 index 00000000..40e1e89a --- /dev/null +++ b/fingerprint_pro_server_api_sdk/models/search_events_response.py @@ -0,0 +1,96 @@ +# coding: utf-8 + +""" + Fingerprint Pro Server API + + Fingerprint Pro Server API allows you to get information about visitors and about individual events in a server environment. It can be used for data exports, decision-making, and data analysis scenarios. Server API is intended for server-side usage, it's not intended to be used from the client side, whether it's a browser or a mobile device. # noqa: E501 + + OpenAPI spec version: 3 + Contact: support@fingerprint.com + Generated by: https://github.com/swagger-api/swagger-codegen.git +""" + +import re # noqa: F401 +from typing import Dict, List, Optional # noqa: F401 +from fingerprint_pro_server_api_sdk.base_model import BaseModel +from fingerprint_pro_server_api_sdk.models.search_events_response_events import SearchEventsResponseEvents + + +class SearchEventsResponse(BaseModel): + """ + Contains a list of all identification events matching the specified search criteria. + + NOTE: This class is auto generated by the swagger code generator program. + + Do not edit the class manually. + """ + """ + Attributes: + swagger_types (dict): The key is attribute name + and the value is attribute type. + attribute_map (dict): The key is attribute name + and the value is json key in definition. + """ + swagger_types = { + 'events': 'list[SearchEventsResponseEvents]', + 'pagination_key': 'str' + } + + nullable_map = { + 'events': False, + 'pagination_key': False + } + + attribute_map = { + 'events': 'events', + 'pagination_key': 'paginationKey' + } + + def __init__(self, events=None, pagination_key=None): # noqa: E501 + """SearchEventsResponse - a model defined in Swagger""" # noqa: E501 + self._events = None + self._pagination_key = None + self.discriminator = None + if events is not None: + self.events = events + if pagination_key is not None: + self.pagination_key = pagination_key + + @property + def events(self) -> Optional[List[SearchEventsResponseEvents]]: + """Gets the events of this SearchEventsResponse. # noqa: E501 + + + :return: The events of this SearchEventsResponse. # noqa: E501 + """ + return self._events + + @events.setter + def events(self, events: Optional[List[SearchEventsResponseEvents]]): + """Sets the events of this SearchEventsResponse. + + + :param events: The events of this SearchEventsResponse. # noqa: E501 + """ + + self._events = events + + @property + def pagination_key(self) -> Optional[str]: + """Gets the pagination_key of this SearchEventsResponse. # noqa: E501 + + + :return: The pagination_key of this SearchEventsResponse. # noqa: E501 + """ + return self._pagination_key + + @pagination_key.setter + def pagination_key(self, pagination_key: Optional[str]): + """Sets the pagination_key of this SearchEventsResponse. + + + :param pagination_key: The pagination_key of this SearchEventsResponse. # noqa: E501 + """ + + self._pagination_key = pagination_key + diff --git a/fingerprint_pro_server_api_sdk/models/search_events_response_events.py b/fingerprint_pro_server_api_sdk/models/search_events_response_events.py new file mode 100644 index 00000000..1926a40c --- /dev/null +++ b/fingerprint_pro_server_api_sdk/models/search_events_response_events.py @@ -0,0 +1,72 @@ +# coding: utf-8 + +""" + Fingerprint Pro Server API + + Fingerprint Pro Server API allows you to get information about visitors and about individual events in a server environment. It can be used for data exports, decision-making, and data analysis scenarios. Server API is intended for server-side usage, it's not intended to be used from the client side, whether it's a browser or a mobile device. # noqa: E501 + + OpenAPI spec version: 3 + Contact: support@fingerprint.com + Generated by: https://github.com/swagger-api/swagger-codegen.git +""" + +import re # noqa: F401 +from typing import Dict, List, Optional # noqa: F401 +from fingerprint_pro_server_api_sdk.base_model import BaseModel +from fingerprint_pro_server_api_sdk.models.products import Products + + +class SearchEventsResponseEvents(BaseModel): + """ + Device intelligence results for the identification event. + + NOTE: This class is auto generated by the swagger code generator program. + + Do not edit the class manually. + """ + """ + Attributes: + swagger_types (dict): The key is attribute name + and the value is attribute type. + attribute_map (dict): The key is attribute name + and the value is json key in definition. + """ + swagger_types = { + 'products': 'Products' + } + + nullable_map = { + 'products': False + } + + attribute_map = { + 'products': 'products' + } + + def __init__(self, products=None): # noqa: E501 + """SearchEventsResponseEvents - a model defined in Swagger""" # noqa: E501 + self._products = None + self.discriminator = None + self.products = products + + @property + def products(self) -> Products: + """Gets the products of this SearchEventsResponseEvents. # noqa: E501 + + + :return: The products of this SearchEventsResponseEvents. # noqa: E501 + """ + return self._products + + @products.setter + def products(self, products: Products): + """Sets the products of this SearchEventsResponseEvents. + + + :param products: The products of this SearchEventsResponseEvents. # noqa: E501 + """ + if products is None: + raise ValueError("Invalid value for `products`, must not be `None`") # noqa: E501 + + self._products = products + diff --git a/res/fingerprint-server-api.yaml b/res/fingerprint-server-api.yaml index af3cc9bd..fd40920f 100644 --- a/res/fingerprint-server-api.yaml +++ b/res/fingerprint-server-api.yaml @@ -142,6 +142,131 @@ paths: application/json: schema: $ref: '#/components/schemas/ErrorResponse' + /events/search: + get: + tags: + - Fingerprint + operationId: searchEvents + summary: Get events via search + description: > + Search for identification events, including Smart Signals, using + multiple filtering criteria. If you don't provide `start` or `end` + parameters, the default search range is the last 7 days. + + + Please note that events include mobile signals (e.g. `rootApps`) even if + the request originated from a non-mobile platform. We recommend you + **ignore** mobile signals for such requests. + parameters: + - name: limit + in: query + required: true + schema: + type: integer + format: int32 + minimum: 1 + example: 10 + description: | + Limit the number of events returned. + - name: visitor_id + in: query + schema: + type: string + description: > + Unique [visitor + identifier](https://dev.fingerprint.com/reference/get-function#visitorid) + issued by Fingerprint Pro. + + Filter for events matching this `visitor_id`. + - name: bot + in: query + schema: + type: string + enum: + - all + - good + - bad + - none + description: | + Filter events by the bot detection result, specifically: + - events where any kind of bot was detected. + - events where a good bot was detected. + - events where a bad bot was detected. + - events where no bot was detected. + - name: ip_address + in: query + schema: + type: string + description: > + Filter events by IP address range. The range can be as specific as a + single IP (/32 for IPv4 or /128 for IPv6) + + All ip_address filters must use CIDR notation, for example, + 10.0.0.0/24, 192.168.0.1/32 + - name: linked_id + in: query + schema: + type: string + description: > + Filter events by your custom identifier. + + + You can use [linked + IDs](https://dev.fingerprint.com/reference/get-function#linkedid) to + associate identification requests with your own identifier, for + example, session ID, purchase ID, or transaction ID. You can then + use this `linked_id` parameter to retrieve all events associated + with your custom identifier. + - name: start + in: query + schema: + type: integer + format: int64 + description: > + Filter events with a timestamp greater than the start time, in Unix + time (milliseconds). + - name: end + in: query + schema: + type: integer + format: int64 + description: > + Filter events with a timestamp smaller than the end time, in Unix + time (milliseconds). + - name: reverse + in: query + schema: + type: boolean + description: | + Sort events in reverse timestamp order. + - name: suspect + in: query + schema: + type: boolean + description: > + Filter events previously tagged as suspicious via the [Update + API](https://dev.fingerprint.com/reference/updateevent). + responses: + '200': + description: Events matching the filter(s). + content: + application/json: + schema: + $ref: '#/components/schemas/SearchEventsResponse' + '400': + description: >- + Bad request. One or more supplied search parameters are invalid, or + a required parameter is missing. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden. Access to this API is denied. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' /visitors/{visitor_id}: get: tags: @@ -1874,6 +1999,25 @@ components: suspect: type: boolean description: Suspect flag indicating observed suspicious or fraudulent event + SearchEventsResponse: + type: object + description: >- + Contains a list of all identification events matching the specified + search criteria. + additionalProperties: false + properties: + events: + type: array + items: + type: object + description: Device intelligence results for the identification event. + required: + - products + properties: + products: + $ref: '#/components/schemas/Products' + paginationKey: + type: string Visit: type: object additionalProperties: false From 966b7960558abab22240b4f30132f43dd32e07d4 Mon Sep 17 00:00:00 2001 From: Ilya Taratukhin Date: Wed, 5 Feb 2025 13:05:52 +0100 Subject: [PATCH 2/7] chore: remove not related changelogs (were introduced before) --- .changeset/forty-seas-prove.md | 5 ----- .changeset/orange-poets-drive.md | 5 ----- 2 files changed, 10 deletions(-) delete mode 100644 .changeset/forty-seas-prove.md delete mode 100644 .changeset/orange-poets-drive.md diff --git a/.changeset/forty-seas-prove.md b/.changeset/forty-seas-prove.md deleted file mode 100644 index b2e8f0e8..00000000 --- a/.changeset/forty-seas-prove.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'fingerprint-pro-server-api-python-sdk': minor ---- - -Add `relay` detection method to the VPN Detection Smart Signal diff --git a/.changeset/orange-poets-drive.md b/.changeset/orange-poets-drive.md deleted file mode 100644 index 0c1a1fd8..00000000 --- a/.changeset/orange-poets-drive.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'fingerprint-pro-server-api-python-sdk': minor ---- - -**events**: Add a `suspect` field to the `identification` product schema \ No newline at end of file From ab115e842a041ffc332e2f0f3a455703f1a8a17e Mon Sep 17 00:00:00 2001 From: Ilya Taratukhin Date: Wed, 5 Feb 2025 16:47:28 +0100 Subject: [PATCH 3/7] test: add tests for search events method --- test/test_fingerprint_api.py | 91 ++++++++++++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 3 deletions(-) diff --git a/test/test_fingerprint_api.py b/test/test_fingerprint_api.py index 97583da2..a1e421b3 100644 --- a/test/test_fingerprint_api.py +++ b/test/test_fingerprint_api.py @@ -11,15 +11,14 @@ """ import io -import json import os import unittest -from datetime import datetime import urllib3 from fingerprint_pro_server_api_sdk import (Configuration, ErrorResponse, ErrorPlainResponse, ErrorCode, - RawDeviceAttributes, EventsUpdateRequest, RelatedVisitorsResponse) + RawDeviceAttributes, EventsUpdateRequest, RelatedVisitorsResponse, + SearchEventsResponse, SearchEventsResponseEvents, Products) from fingerprint_pro_server_api_sdk.api.fingerprint_api import FingerprintApi # noqa: E501 from fingerprint_pro_server_api_sdk.rest import KnownApiException, ApiException from urllib.parse import urlencode @@ -69,6 +68,9 @@ MOCK_GET_RELATED_VISITORS_404 = '404_visitor_not_found.json' # errors/ MOCK_GET_RELATED_VISITORS_429 = '429_too_many_requests.json' # errors/ +MOCK_SEARCH_EVENTS_200 = 'get_event_search_200.json' +MOCK_SEARCH_EVENTS_400 = '400_ip_address_invalid.json' # errors/ +MOCK_SEARCH_EVENTS_403 = '403_feature_not_enabled.json' # errors/ class MockPoolManager(object): @@ -120,6 +122,11 @@ def request(self, *args, **kwargs): if mock_file_by_first_argument == 'related-visitors': # Extract file name from visitor_id param mock_file_by_first_argument = r[1]['fields'][1][1] + if mock_file_by_first_argument == 'search': + if status == 200: + mock_file_by_first_argument = MOCK_SEARCH_EVENTS_200 + else: + mock_file_by_first_argument = r[1]['fields'][2][1] path = './test/mocks/' + mock_file_by_first_argument @@ -182,6 +189,15 @@ def get_related_visitors_path(region='us'): }.get(region, "api.fpjs.io") return 'https://%s/related-visitors' % domain + @staticmethod + def get_search_events_path(region='us'): + domain = { + "us": "api.fpjs.io", + "eu": "eu.api.fpjs.io", + "ap": "ap.api.fpjs.io", + }.get(region, "api.fpjs.io") + return 'https://%s/events/search' % domain + def test_get_visits_correct_data(self): """Test checks correct code run result in default scenario""" mock_pool = MockPoolManager(self) @@ -663,6 +679,75 @@ def test_get_related_visitors_429(self): self.assertEqual(context.exception.structured_error.error.code, ErrorCode.TOOMANYREQUESTS) self.assertEqual(context.exception.structured_error.retry_after, 4) + def test_search_events_only_limit(self): + """Test that search events returns 200 with only limit param""" + mock_pool = MockPoolManager(self) + self.api.api_client.rest_client.pool_manager = mock_pool + mock_pool.expect_request('GET', TestFingerprintApi.get_search_events_path(), + fields=[self.integration_info, ('limit', 1)], + headers=self.request_headers, preload_content=True, timeout=None) + + response = self.api.search_events(1) + self.assertIsInstance(response, SearchEventsResponse) + event_response = response.events[0] + self.assertIsInstance(event_response, SearchEventsResponseEvents) + self.assertIsInstance(event_response.products, Products) + self.assertIsInstance(event_response.products.raw_device_attributes.data, RawDeviceAttributes) + + def test_search_events_all_params(self): + """Test that search events returns 200 with all params""" + LIMIT = 100 + BOT = 'good' + IP_ADDRESS = '10.0.0.0/24' + LINKED_ID = 'some_linked_id' + START = 1582299576511 + END = 1582299576513 + REVERSE = True + SUSPECT = False + mock_pool = MockPoolManager(self) + self.api.api_client.rest_client.pool_manager = mock_pool + mock_pool.expect_request('GET', TestFingerprintApi.get_search_events_path(), + fields=[self.integration_info, ('limit', LIMIT), + ('visitor_id', MOCK_SEARCH_EVENTS_200), ('bot', BOT), + ('ip_address', IP_ADDRESS), ('linked_id', LINKED_ID), ('start', START), + ('end', END), ('reverse', REVERSE), ('suspect', SUSPECT)], + headers=self.request_headers, preload_content=True, timeout=None) + + response = self.api.search_events(LIMIT, visitor_id=MOCK_SEARCH_EVENTS_200, bot=BOT, ip_address=IP_ADDRESS, + linked_id=LINKED_ID, start=START, end=END, reverse=REVERSE, suspect=SUSPECT) + self.assertIsInstance(response, SearchEventsResponse) + event_response = response.events[0] + self.assertIsInstance(event_response, SearchEventsResponseEvents) + self.assertIsInstance(event_response.products, Products) + self.assertIsInstance(event_response.products.raw_device_attributes.data, RawDeviceAttributes) + + def test_search_events_400(self): + """Test that search events returns 400 invalid ip address""" + mock_pool = MockPoolManager(self) + self.api.api_client.rest_client.pool_manager = mock_pool + mock_pool.expect_request('GET', TestFingerprintApi.get_search_events_path(), + fields=[self.integration_info, ('limit', 1), ('visitor_id', MOCK_SEARCH_EVENTS_400)], + headers=self.request_headers, preload_content=True, timeout=None, status=400) + + with self.assertRaises(KnownApiException) as context: + self.api.search_events(1, visitor_id=MOCK_SEARCH_EVENTS_400) + self.assertEqual(context.exception.status, 400) + self.assertIsInstance(context.exception.structured_error, ErrorResponse) + self.assertEqual(context.exception.structured_error.error.code, ErrorCode.REQUESTCANNOTBEPARSED) + + def test_search_events_403(self): + """Test that search events returns 403 feature not enabled""" + mock_pool = MockPoolManager(self) + self.api.api_client.rest_client.pool_manager = mock_pool + mock_pool.expect_request('GET', TestFingerprintApi.get_search_events_path(), + fields=[self.integration_info, ('limit', 1), ('visitor_id', MOCK_SEARCH_EVENTS_403)], + headers=self.request_headers, preload_content=True, timeout=None, status=403) + + with self.assertRaises(KnownApiException) as context: + self.api.search_events(1, visitor_id=MOCK_SEARCH_EVENTS_403) + self.assertEqual(context.exception.status, 403) + self.assertIsInstance(context.exception.structured_error, ErrorResponse) + self.assertEqual(context.exception.structured_error.error.code, ErrorCode.FEATURENOTENABLED) if __name__ == '__main__': unittest.main() From 95d6661d98a6f3c4174a5a08308419af57fb9f64 Mon Sep 17 00:00:00 2001 From: Ilya Taratukhin Date: Wed, 5 Feb 2025 17:48:39 +0100 Subject: [PATCH 4/7] docs: add search events usage example to the readme --- README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/README.md b/README.md index 97dad6e9..21687655 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,36 @@ except ApiException as e: print("Exception when calling FingerprintApi->get_event: %s\n" % e) ``` +Search events with custom filters: +```python +import fingerprint_pro_server_api_sdk +from fingerprint_pro_server_api_sdk.rest import ApiException, KnownApiException + +configuration = fingerprint_pro_server_api_sdk.Configuration(api_key="SECRET_API_KEY") +api_instance = fingerprint_pro_server_api_sdk.FingerprintApi(configuration) + +limit = 20 # int | Limit the number of events returned. +visitor_id = 'VISITOR_ID' # str | Unique [visitor identifier](https://dev.fingerprint.com/reference/get-function#visitorid) issued by Fingerprint Pro. Filter for events matching this `visitor_id`. (optional) +bot = 'good' # str | Filter events by the bot detection result, specifically: events where <'any'|'good'|'bad'|'none'> kind of bot was detected. (optional) +ip_address = '192.168.0.1/32' # str | Filter events by IP address range. The range can be as specific as a single IP (/32 for IPv4 or /128 for IPv6) All ip_address filters must use CIDR notation, for example, 10.0.0.0/24, 192.168.0.1/32 (optional) +linked_id = 'linked_id_example' # str | Filter events by your custom identifier. You can use [linked IDs](https://dev.fingerprint.com/reference/get-function#linkedid) to associate identification requests with your own identifier, for example, session ID, purchase ID, or transaction ID. You can then use this `linked_id` parameter to retrieve all events associated with your custom identifier. (optional) +start = 1738687200000 # int | Filter events with a timestamp greater than the start time, in Unix time (milliseconds). (optional) +end = 1738773600000 # int | Filter events with a timestamp smaller than the end time, in Unix time (milliseconds). (optional) +reverse = True # bool | Sort events in reverse timestamp order. (optional) +suspect = False # bool | Filter events previously tagged as suspicious via the [Update API](https://dev.fingerprint.com/reference/updateevent). (optional) + +try: + # Get events via search + api_response = api_instance.search_events(limit, visitor_id=visitor_id, bot=bot, ip_address=ip_address, linked_id=linked_id, start=start, end=end, reverse=reverse, suspect=suspect) + print(api_response) + +except KnownApiException as e: + structured_error = e.structured_error + print("Error code: %s. Error message: %s\n" % (structured_error.error.code, structured_error.error.message)) +except ApiException as e: + print("Exception when calling FingerprintApi->get_event: %s\n" % e) +``` + Update event for requestId: ```python import fingerprint_pro_server_api_sdk From 5fe60d0ecbadbc9902d502848ad48341ed72e7bd Mon Sep 17 00:00:00 2001 From: Ilya Taratukhin Date: Wed, 5 Feb 2025 19:04:32 +0100 Subject: [PATCH 5/7] test: add search events call to functional tests --- run_checks.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/run_checks.py b/run_checks.py index e4d4f3d9..f075e559 100644 --- a/run_checks.py +++ b/run_checks.py @@ -31,11 +31,18 @@ events_response = api_instance.get_event(request_id) print("\n\n\nEvent response: \n", events_response.products) - except ApiException as e: print("Exception when calling DefaultApi->get_event: %s\n" % e) exit(1) +try: + search_events_response = api_instance.search_events(2, bot="bad") + print("\n\n\nSearch events response: \n", search_events_response) + +except ApiException as e: + print("Exception when calling DefaultApi->search_events: %s\n" % e) + exit(1) + # Async methods examples try: visits_response_request = api_instance.get_visits(visitor_id, limit=2, async_req=True) From 7a155c04df6468052d9a2540edb60987ee226ede Mon Sep 17 00:00:00 2001 From: Ilya Taratukhin Date: Wed, 5 Feb 2025 19:33:41 +0100 Subject: [PATCH 6/7] chore: update missed template --- template/README.mustache | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/template/README.mustache b/template/README.mustache index 983010ff..ab8ff7e0 100644 --- a/template/README.mustache +++ b/template/README.mustache @@ -155,6 +155,36 @@ except ApiException as e: print("Exception when calling FingerprintApi->get_event: %s\n" % e) ``` +Search events with custom filters: +```python +import fingerprint_pro_server_api_sdk +from fingerprint_pro_server_api_sdk.rest import ApiException, KnownApiException + +configuration = fingerprint_pro_server_api_sdk.Configuration(api_key="SECRET_API_KEY") +api_instance = fingerprint_pro_server_api_sdk.FingerprintApi(configuration) + +limit = 20 # int | Limit the number of events returned. +visitor_id = 'VISITOR_ID' # str | Unique [visitor identifier](https://dev.fingerprint.com/reference/get-function#visitorid) issued by Fingerprint Pro. Filter for events matching this `visitor_id`. (optional) +bot = 'good' # str | Filter events by the bot detection result, specifically: events where <'any'|'good'|'bad'|'none'> kind of bot was detected. (optional) +ip_address = '192.168.0.1/32' # str | Filter events by IP address range. The range can be as specific as a single IP (/32 for IPv4 or /128 for IPv6) All ip_address filters must use CIDR notation, for example, 10.0.0.0/24, 192.168.0.1/32 (optional) +linked_id = 'linked_id_example' # str | Filter events by your custom identifier. You can use [linked IDs](https://dev.fingerprint.com/reference/get-function#linkedid) to associate identification requests with your own identifier, for example, session ID, purchase ID, or transaction ID. You can then use this `linked_id` parameter to retrieve all events associated with your custom identifier. (optional) +start = 1738687200000 # int | Filter events with a timestamp greater than the start time, in Unix time (milliseconds). (optional) +end = 1738773600000 # int | Filter events with a timestamp smaller than the end time, in Unix time (milliseconds). (optional) +reverse = True # bool | Sort events in reverse timestamp order. (optional) +suspect = False # bool | Filter events previously tagged as suspicious via the [Update API](https://dev.fingerprint.com/reference/updateevent). (optional) + +try: + # Get events via search + api_response = api_instance.search_events(limit, visitor_id=visitor_id, bot=bot, ip_address=ip_address, linked_id=linked_id, start=start, end=end, reverse=reverse, suspect=suspect) + print(api_response) + +except KnownApiException as e: + structured_error = e.structured_error + print("Error code: %s. Error message: %s\n" % (structured_error.error.code, structured_error.error.message)) +except ApiException as e: + print("Exception when calling FingerprintApi->get_event: %s\n" % e) +``` + Update event for requestId: ```python import {{packageName}} From 2fe4e509b45918fc42bb35f7bced091b20448d9d Mon Sep 17 00:00:00 2001 From: Ilya Taratukhin Date: Thu, 6 Feb 2025 20:31:02 +0100 Subject: [PATCH 7/7] test: add test case for search events with part of the params provided --- test/test_fingerprint_api.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/test_fingerprint_api.py b/test/test_fingerprint_api.py index a1e421b3..39040b3f 100644 --- a/test/test_fingerprint_api.py +++ b/test/test_fingerprint_api.py @@ -721,6 +721,29 @@ def test_search_events_all_params(self): self.assertIsInstance(event_response.products, Products) self.assertIsInstance(event_response.products.raw_device_attributes.data, RawDeviceAttributes) + def test_search_events_partial_params(self): + """Test that search events returns 200 with partial params provided""" + LIMIT = 100 + BOT = 'good' + LINKED_ID = 'some_linked_id' + START = 1582299576511 + REVERSE = True + mock_pool = MockPoolManager(self) + self.api.api_client.rest_client.pool_manager = mock_pool + mock_pool.expect_request('GET', TestFingerprintApi.get_search_events_path(), + fields=[self.integration_info, ('limit', LIMIT), + ('visitor_id', MOCK_SEARCH_EVENTS_200), ('bot', BOT), + ('linked_id', LINKED_ID), ('start', START), ('reverse', REVERSE)], + headers=self.request_headers, preload_content=True, timeout=None) + + response = self.api.search_events(LIMIT, visitor_id=MOCK_SEARCH_EVENTS_200, bot=BOT, linked_id=LINKED_ID, + start=START, reverse=REVERSE) + self.assertIsInstance(response, SearchEventsResponse) + event_response = response.events[0] + self.assertIsInstance(event_response, SearchEventsResponseEvents) + self.assertIsInstance(event_response.products, Products) + self.assertIsInstance(event_response.products.raw_device_attributes.data, RawDeviceAttributes) + def test_search_events_400(self): """Test that search events returns 400 invalid ip address""" mock_pool = MockPoolManager(self)