diff --git a/.codegen.json b/.codegen.json index 70338db..1d4b2c8 100644 --- a/.codegen.json +++ b/.codegen.json @@ -1 +1 @@ -{ "engineHash": "edc49a6", "specHash": "6ca858e", "version": "1.4.1" } +{ "engineHash": "5d1b305", "specHash": "6ca858e", "version": "1.4.1" } diff --git a/box_sdk_gen/client.py b/box_sdk_gen/client.py index c781d31..1b7d1f1 100644 --- a/box_sdk_gen/client.py +++ b/box_sdk_gen/client.py @@ -170,6 +170,8 @@ from box_sdk_gen.networking.base_urls import BaseUrls +from box_sdk_gen.networking.proxy_config import ProxyConfig + class BoxClient: def __init__(self, auth: Authentication, *, network_session: NetworkSession = None): @@ -439,3 +441,11 @@ def with_custom_base_urls(self, base_urls: BaseUrls) -> 'BoxClient': auth=self.auth, network_session=self.network_session.with_custom_base_urls(base_urls), ) + + def with_proxy(self, config: ProxyConfig) -> 'BoxClient': + """ + Create a new client with a custom proxy that will be used for every API call + """ + return BoxClient( + auth=self.auth, network_session=self.network_session.with_proxy(config) + ) diff --git a/box_sdk_gen/managers/events.py b/box_sdk_gen/managers/events.py index 6d996ba..0344b09 100644 --- a/box_sdk_gen/managers/events.py +++ b/box_sdk_gen/managers/events.py @@ -2,20 +2,20 @@ from typing import Optional -from typing import List - from typing import Dict -from box_sdk_gen.internal.utils import to_string - from box_sdk_gen.serialization.json.serializer import deserialize -from box_sdk_gen.schemas.events import Events +from typing import List -from box_sdk_gen.schemas.client_error import ClientError +from box_sdk_gen.internal.utils import to_string from box_sdk_gen.schemas.realtime_servers import RealtimeServers +from box_sdk_gen.schemas.client_error import ClientError + +from box_sdk_gen.schemas.events import Events + from box_sdk_gen.networking.auth import Authentication from box_sdk_gen.networking.network import NetworkSession @@ -26,10 +26,6 @@ from box_sdk_gen.internal.utils import ByteStream -from box_sdk_gen.internal.utils import DateTime - -from box_sdk_gen.serialization.json.json_data import sd_to_json - from box_sdk_gen.networking.fetch import FetchOptions from box_sdk_gen.networking.fetch import FetchResponse @@ -38,6 +34,10 @@ from box_sdk_gen.serialization.json.json_data import SerializedData +from box_sdk_gen.internal.utils import DateTime + +from box_sdk_gen.serialization.json.json_data import sd_to_json + class GetEventsStreamType(str, Enum): ALL = 'all' @@ -191,6 +191,101 @@ def __init__( self.auth = auth self.network_session = network_session + def get_events_with_long_polling( + self, *, extra_headers: Optional[Dict[str, Optional[str]]] = None + ) -> RealtimeServers: + """ + Returns a list of real-time servers that can be used for long-polling updates + + to the [event stream](#get-events). + + + Long polling is the concept where a HTTP request is kept open until the + + + server sends a response, then repeating the process over and over to receive + + + updated responses. + + + Long polling the event stream can only be used for user events, not for + + + enterprise events. + + + To use long polling, first use this endpoint to retrieve a list of long poll + + + URLs. Next, make a long poll request to any of the provided URLs. + + + When an event occurs in monitored account a response with the value + + + `new_change` will be sent. The response contains no other details as + + + it only serves as a prompt to take further action such as sending a + + + request to the [events endpoint](#get-events) with the last known + + + `stream_position`. + + + After the server sends this response it closes the connection. You must now + + + repeat the long poll process to begin listening for events again. + + + If no events occur for a while and the connection times out you will + + + receive a response with the value `reconnect`. When you receive this response + + + you’ll make another call to this endpoint to restart the process. + + + If you receive no events in `retry_timeout` seconds then you will need to + + + make another request to the real-time server (one of the URLs in the response + + + for this endpoint). This might be necessary due to network errors. + + + Finally, if you receive a `max_retries` error when making a request to the + + + real-time server, you should start over by making a call to this endpoint + + + first. + + :param extra_headers: Extra headers that will be included in the HTTP request., defaults to None + :type extra_headers: Optional[Dict[str, Optional[str]]], optional + """ + if extra_headers is None: + extra_headers = {} + headers_map: Dict[str, str] = prepare_params({**extra_headers}) + response: FetchResponse = fetch( + FetchOptions( + url=''.join([self.network_session.base_urls.base_url, '/2.0/events']), + method='OPTIONS', + headers=headers_map, + response_format='json', + auth=self.auth, + network_session=self.network_session, + ) + ) + return deserialize(response.data, RealtimeServers) + def get_events( self, *, @@ -300,98 +395,3 @@ def get_events( ) ) return deserialize(response.data, Events) - - def get_events_with_long_polling( - self, *, extra_headers: Optional[Dict[str, Optional[str]]] = None - ) -> RealtimeServers: - """ - Returns a list of real-time servers that can be used for long-polling updates - - to the [event stream](#get-events). - - - Long polling is the concept where a HTTP request is kept open until the - - - server sends a response, then repeating the process over and over to receive - - - updated responses. - - - Long polling the event stream can only be used for user events, not for - - - enterprise events. - - - To use long polling, first use this endpoint to retrieve a list of long poll - - - URLs. Next, make a long poll request to any of the provided URLs. - - - When an event occurs in monitored account a response with the value - - - `new_change` will be sent. The response contains no other details as - - - it only serves as a prompt to take further action such as sending a - - - request to the [events endpoint](#get-events) with the last known - - - `stream_position`. - - - After the server sends this response it closes the connection. You must now - - - repeat the long poll process to begin listening for events again. - - - If no events occur for a while and the connection times out you will - - - receive a response with the value `reconnect`. When you receive this response - - - you’ll make another call to this endpoint to restart the process. - - - If you receive no events in `retry_timeout` seconds then you will need to - - - make another request to the real-time server (one of the URLs in the response - - - for this endpoint). This might be necessary due to network errors. - - - Finally, if you receive a `max_retries` error when making a request to the - - - real-time server, you should start over by making a call to this endpoint - - - first. - - :param extra_headers: Extra headers that will be included in the HTTP request., defaults to None - :type extra_headers: Optional[Dict[str, Optional[str]]], optional - """ - if extra_headers is None: - extra_headers = {} - headers_map: Dict[str, str] = prepare_params({**extra_headers}) - response: FetchResponse = fetch( - FetchOptions( - url=''.join([self.network_session.base_urls.base_url, '/2.0/events']), - method='OPTIONS', - headers=headers_map, - response_format='json', - auth=self.auth, - network_session=self.network_session, - ) - ) - return deserialize(response.data, RealtimeServers) diff --git a/box_sdk_gen/managers/file_versions.py b/box_sdk_gen/managers/file_versions.py index 4809f5b..7d46a0b 100644 --- a/box_sdk_gen/managers/file_versions.py +++ b/box_sdk_gen/managers/file_versions.py @@ -199,24 +199,18 @@ def get_file_version_by_id( ) return deserialize(response.data, FileVersionFull) - def update_file_version_by_id( + def delete_file_version_by_id( self, file_id: str, file_version_id: str, *, - trashed_at: Union[Optional[str], NullValue] = None, + if_match: Optional[str] = None, extra_headers: Optional[Dict[str, Optional[str]]] = None - ) -> FileVersionFull: + ) -> None: """ - Restores a specific version of a file after it was deleted. - - Don't use this endpoint to restore Box Notes, - - - as it works with file formats such as PDF, DOC, - + Move a file version to the trash. - PPTX or similar. + Versions are only tracked for Box users with premium accounts. :param file_id: The unique identifier that represents a file. @@ -230,16 +224,22 @@ def update_file_version_by_id( :param file_version_id: The ID of the file version Example: "1234" :type file_version_id: str - :param trashed_at: Set this to `null` to clear - the date and restore the file., defaults to None - :type trashed_at: Union[Optional[str], NullValue], optional + :param if_match: Ensures this item hasn't recently changed before + making changes. + + Pass in the item's last observed `etag` value + into this header and the endpoint will fail + with a `412 Precondition Failed` if it + has changed since., defaults to None + :type if_match: Optional[str], optional :param extra_headers: Extra headers that will be included in the HTTP request., defaults to None :type extra_headers: Optional[Dict[str, Optional[str]]], optional """ if extra_headers is None: extra_headers = {} - request_body: Dict = {'trashed_at': trashed_at} - headers_map: Dict[str, str] = prepare_params({**extra_headers}) + headers_map: Dict[str, str] = prepare_params( + {'if-match': to_string(if_match), **extra_headers} + ) response: FetchResponse = fetch( FetchOptions( url=''.join( @@ -251,29 +251,33 @@ def update_file_version_by_id( to_string(file_version_id), ] ), - method='PUT', + method='DELETE', headers=headers_map, - data=serialize(request_body), - content_type='application/json', - response_format='json', + response_format=None, auth=self.auth, network_session=self.network_session, ) ) - return deserialize(response.data, FileVersionFull) + return None - def delete_file_version_by_id( + def update_file_version_by_id( self, file_id: str, file_version_id: str, *, - if_match: Optional[str] = None, + trashed_at: Union[Optional[str], NullValue] = None, extra_headers: Optional[Dict[str, Optional[str]]] = None - ) -> None: + ) -> FileVersionFull: """ - Move a file version to the trash. + Restores a specific version of a file after it was deleted. - Versions are only tracked for Box users with premium accounts. + Don't use this endpoint to restore Box Notes, + + + as it works with file formats such as PDF, DOC, + + + PPTX or similar. :param file_id: The unique identifier that represents a file. @@ -287,22 +291,16 @@ def delete_file_version_by_id( :param file_version_id: The ID of the file version Example: "1234" :type file_version_id: str - :param if_match: Ensures this item hasn't recently changed before - making changes. - - Pass in the item's last observed `etag` value - into this header and the endpoint will fail - with a `412 Precondition Failed` if it - has changed since., defaults to None - :type if_match: Optional[str], optional + :param trashed_at: Set this to `null` to clear + the date and restore the file., defaults to None + :type trashed_at: Union[Optional[str], NullValue], optional :param extra_headers: Extra headers that will be included in the HTTP request., defaults to None :type extra_headers: Optional[Dict[str, Optional[str]]], optional """ if extra_headers is None: extra_headers = {} - headers_map: Dict[str, str] = prepare_params( - {'if-match': to_string(if_match), **extra_headers} - ) + request_body: Dict = {'trashed_at': trashed_at} + headers_map: Dict[str, str] = prepare_params({**extra_headers}) response: FetchResponse = fetch( FetchOptions( url=''.join( @@ -314,14 +312,16 @@ def delete_file_version_by_id( to_string(file_version_id), ] ), - method='DELETE', + method='PUT', headers=headers_map, - response_format=None, + data=serialize(request_body), + content_type='application/json', + response_format='json', auth=self.auth, network_session=self.network_session, ) ) - return None + return deserialize(response.data, FileVersionFull) def promote_file_version( self, diff --git a/box_sdk_gen/managers/shield_information_barrier_segments.py b/box_sdk_gen/managers/shield_information_barrier_segments.py index d8c9e0a..56d3e27 100644 --- a/box_sdk_gen/managers/shield_information_barrier_segments.py +++ b/box_sdk_gen/managers/shield_information_barrier_segments.py @@ -94,30 +94,25 @@ def get_shield_information_barrier_segment_by_id( ) return deserialize(response.data, ShieldInformationBarrierSegment) - def update_shield_information_barrier_segment_by_id( + def delete_shield_information_barrier_segment_by_id( self, shield_information_barrier_segment_id: str, *, - name: Optional[str] = None, - description: Union[Optional[str], NullValue] = None, extra_headers: Optional[Dict[str, Optional[str]]] = None - ) -> ShieldInformationBarrierSegment: + ) -> None: """ - Updates the shield information barrier segment based on provided ID.. + Deletes the shield information barrier segment + + based on provided ID. + :param shield_information_barrier_segment_id: The ID of the shield information barrier segment. Example: "3423" :type shield_information_barrier_segment_id: str - :param name: The updated name for the shield information barrier segment., defaults to None - :type name: Optional[str], optional - :param description: The updated description for - the shield information barrier segment., defaults to None - :type description: Union[Optional[str], NullValue], optional :param extra_headers: Extra headers that will be included in the HTTP request., defaults to None :type extra_headers: Optional[Dict[str, Optional[str]]], optional """ if extra_headers is None: extra_headers = {} - request_body: Dict = {'name': name, 'description': description} headers_map: Dict[str, str] = prepare_params({**extra_headers}) response: FetchResponse = fetch( FetchOptions( @@ -128,36 +123,39 @@ def update_shield_information_barrier_segment_by_id( to_string(shield_information_barrier_segment_id), ] ), - method='PUT', + method='DELETE', headers=headers_map, - data=serialize(request_body), - content_type='application/json', - response_format='json', + response_format=None, auth=self.auth, network_session=self.network_session, ) ) - return deserialize(response.data, ShieldInformationBarrierSegment) + return None - def delete_shield_information_barrier_segment_by_id( + def update_shield_information_barrier_segment_by_id( self, shield_information_barrier_segment_id: str, *, + name: Optional[str] = None, + description: Union[Optional[str], NullValue] = None, extra_headers: Optional[Dict[str, Optional[str]]] = None - ) -> None: + ) -> ShieldInformationBarrierSegment: """ - Deletes the shield information barrier segment - - based on provided ID. - + Updates the shield information barrier segment based on provided ID.. :param shield_information_barrier_segment_id: The ID of the shield information barrier segment. Example: "3423" :type shield_information_barrier_segment_id: str + :param name: The updated name for the shield information barrier segment., defaults to None + :type name: Optional[str], optional + :param description: The updated description for + the shield information barrier segment., defaults to None + :type description: Union[Optional[str], NullValue], optional :param extra_headers: Extra headers that will be included in the HTTP request., defaults to None :type extra_headers: Optional[Dict[str, Optional[str]]], optional """ if extra_headers is None: extra_headers = {} + request_body: Dict = {'name': name, 'description': description} headers_map: Dict[str, str] = prepare_params({**extra_headers}) response: FetchResponse = fetch( FetchOptions( @@ -168,14 +166,16 @@ def delete_shield_information_barrier_segment_by_id( to_string(shield_information_barrier_segment_id), ] ), - method='DELETE', + method='PUT', headers=headers_map, - response_format=None, + data=serialize(request_body), + content_type='application/json', + response_format='json', auth=self.auth, network_session=self.network_session, ) ) - return None + return deserialize(response.data, ShieldInformationBarrierSegment) def get_shield_information_barrier_segments( self, diff --git a/box_sdk_gen/managers/uploads.py b/box_sdk_gen/managers/uploads.py index 23c88da..4ebd8a9 100644 --- a/box_sdk_gen/managers/uploads.py +++ b/box_sdk_gen/managers/uploads.py @@ -63,6 +63,16 @@ def __init__( self.content_modified_at = content_modified_at +class PreflightFileUploadCheckParent(BaseObject): + def __init__(self, *, id: Optional[str] = None, **kwargs): + """ + :param id: The ID of parent item, defaults to None + :type id: Optional[str], optional + """ + super().__init__(**kwargs) + self.id = id + + class UploadFileAttributesParentField(BaseObject): def __init__(self, id: str, **kwargs): """ @@ -105,16 +115,6 @@ def __init__( self.content_modified_at = content_modified_at -class PreflightFileUploadCheckParent(BaseObject): - def __init__(self, *, id: Optional[str] = None, **kwargs): - """ - :param id: The ID of parent item, defaults to None - :type id: Optional[str], optional - """ - super().__init__(**kwargs) - self.id = id - - class UploadsManager: def __init__( self, @@ -263,6 +263,46 @@ def upload_file_version( ) return deserialize(response.data, Files) + def preflight_file_upload_check( + self, + *, + name: Optional[str] = None, + size: Optional[int] = None, + parent: Optional[PreflightFileUploadCheckParent] = None, + extra_headers: Optional[Dict[str, Optional[str]]] = None + ) -> UploadUrl: + """ + Performs a check to verify that a file will be accepted by Box + + before you upload the entire file. + + :param name: The name for the file, defaults to None + :type name: Optional[str], optional + :param size: The size of the file in bytes, defaults to None + :type size: Optional[int], optional + :param extra_headers: Extra headers that will be included in the HTTP request., defaults to None + :type extra_headers: Optional[Dict[str, Optional[str]]], optional + """ + if extra_headers is None: + extra_headers = {} + request_body: Dict = {'name': name, 'size': size, 'parent': parent} + headers_map: Dict[str, str] = prepare_params({**extra_headers}) + response: FetchResponse = fetch( + FetchOptions( + url=''.join( + [self.network_session.base_urls.base_url, '/2.0/files/content'] + ), + method='OPTIONS', + headers=headers_map, + data=serialize(request_body), + content_type='application/json', + response_format='json', + auth=self.auth, + network_session=self.network_session, + ) + ) + return deserialize(response.data, UploadUrl) + def upload_file( self, attributes: UploadFileAttributes, @@ -370,43 +410,3 @@ def upload_file( ) ) return deserialize(response.data, Files) - - def preflight_file_upload_check( - self, - *, - name: Optional[str] = None, - size: Optional[int] = None, - parent: Optional[PreflightFileUploadCheckParent] = None, - extra_headers: Optional[Dict[str, Optional[str]]] = None - ) -> UploadUrl: - """ - Performs a check to verify that a file will be accepted by Box - - before you upload the entire file. - - :param name: The name for the file, defaults to None - :type name: Optional[str], optional - :param size: The size of the file in bytes, defaults to None - :type size: Optional[int], optional - :param extra_headers: Extra headers that will be included in the HTTP request., defaults to None - :type extra_headers: Optional[Dict[str, Optional[str]]], optional - """ - if extra_headers is None: - extra_headers = {} - request_body: Dict = {'name': name, 'size': size, 'parent': parent} - headers_map: Dict[str, str] = prepare_params({**extra_headers}) - response: FetchResponse = fetch( - FetchOptions( - url=''.join( - [self.network_session.base_urls.base_url, '/2.0/files/content'] - ), - method='OPTIONS', - headers=headers_map, - data=serialize(request_body), - content_type='application/json', - response_format='json', - auth=self.auth, - network_session=self.network_session, - ) - ) - return deserialize(response.data, UploadUrl) diff --git a/box_sdk_gen/networking/__init__.py b/box_sdk_gen/networking/__init__.py index 5a3ee5c..8f10fe0 100644 --- a/box_sdk_gen/networking/__init__.py +++ b/box_sdk_gen/networking/__init__.py @@ -2,6 +2,8 @@ from box_sdk_gen.networking.network import * +from box_sdk_gen.networking.proxy_config import * + from box_sdk_gen.networking.auth import * from box_sdk_gen.networking.base_urls import * diff --git a/box_sdk_gen/networking/network.py b/box_sdk_gen/networking/network.py index aa86450..b0f2de8 100644 --- a/box_sdk_gen/networking/network.py +++ b/box_sdk_gen/networking/network.py @@ -1,5 +1,7 @@ import requests from typing import Dict + +from .proxy_config import ProxyConfig from .base_urls import BaseUrls @@ -7,7 +9,10 @@ class NetworkSession: MAX_ATTEMPTS = 5 def __init__( - self, additional_headers: Dict[str, str] = None, base_urls: BaseUrls = None + self, + additional_headers: Dict[str, str] = None, + base_urls: BaseUrls = None, + proxy_url: str = None, ): if additional_headers is None: additional_headers = {} @@ -16,6 +21,10 @@ def __init__( self.requests_session = requests.Session() self.additional_headers = additional_headers self.base_urls = base_urls + self.proxy_url = proxy_url + + proxies = {'http': proxy_url, 'https': proxy_url} if proxy_url else {} + self.requests_session.proxies = proxies def with_additional_headers( self, additional_headers: Dict[str, str] = None @@ -27,7 +36,9 @@ def with_additional_headers( :return: a new instance of NetworkSession """ return NetworkSession( - {**self.additional_headers, **additional_headers}, self.base_urls + {**self.additional_headers, **additional_headers}, + self.base_urls, + self.proxy_url, ) def with_custom_base_urls(self, base_urls: BaseUrls) -> 'NetworkSession': @@ -37,4 +48,23 @@ def with_custom_base_urls(self, base_urls: BaseUrls) -> 'NetworkSession': :param base_urls: Dict of base urls, which are appended to each API request :return: a new instance of NetworkSession """ - return NetworkSession(self.additional_headers, base_urls) + return NetworkSession(self.additional_headers, base_urls, self.proxy_url) + + def with_proxy(self, config: ProxyConfig) -> 'NetworkSession': + """ + Generate a fresh network session by duplicating the existing configuration and network parameters, + while also including a proxy to be used for each API call. + :param config: ProxyConfig object, which contains the proxy url, username, and password + :return: a new instance of NetworkSession + """ + if not config.url or not config.url.startswith("http"): + raise ValueError("Invalid proxy URL provided") + + proxy_host = config.url.split("//")[1] + proxy_auth = ( + f'{config.username}:{config.password}@' + if config.username and config.password + else None + ) + proxy_url = f'http://{proxy_auth}{proxy_host}' + return NetworkSession(self.additional_headers, self.base_urls, proxy_url) diff --git a/box_sdk_gen/networking/proxy_config.py b/box_sdk_gen/networking/proxy_config.py new file mode 100644 index 0000000..05d6f12 --- /dev/null +++ b/box_sdk_gen/networking/proxy_config.py @@ -0,0 +1,14 @@ +from typing import Optional + + +class ProxyConfig: + def __init__( + self, + url: str, + *, + username: Optional[str] = None, + password: Optional[str] = None + ): + self.url = url + self.username = username + self.password = password diff --git a/docs/client.md b/docs/client.md index 982faab..d8e6ad6 100644 --- a/docs/client.md +++ b/docs/client.md @@ -6,11 +6,13 @@ divided across resource managers. +- [Client](#client) - [Additional headers](#additional-headers) - [As-User header](#as-user-header) - [Suppress notifications](#suppress-notifications) - [Custom headers](#custom-headers) - [Custom Base URLs](#custom-base-urls) +- [Use Proxy for API calls](#use-proxy-for-api-calls) @@ -77,3 +79,15 @@ new_client = client.with_custom_base_urls( ) ) ``` + +# Use Proxy for API calls + +In order to use a proxy for API calls, calling the `client.with_proxy(proxyConfig)` method creates a new client, leaving the original client unmodified, with the username and password being optional. + +**Note:** We are only supporting http/s proxies with basic authentication. NTLM and other authentication methods are not supported. + +```python +new_client = client.with_proxy( + ProxyConfig(url="http://proxy.com", username="username", password="password") +) +``` diff --git a/docs/events.md b/docs/events.md index ba3ce50..9d2491f 100644 --- a/docs/events.md +++ b/docs/events.md @@ -1,64 +1,7 @@ # EventsManager -- [List user and enterprise events](#list-user-and-enterprise-events) - [Get events long poll endpoint](#get-events-long-poll-endpoint) - -## List user and enterprise events - -Returns up to a year of past events for a given user -or for the entire enterprise. - -By default this returns events for the authenticated user. To retrieve events -for the entire enterprise, set the `stream_type` to `admin_logs_streaming` -for live monitoring of new events, or `admin_logs` for querying across -historical events. The user making the API call will -need to have admin privileges, and the application will need to have the -scope `manage enterprise properties` checked. - -This operation is performed by calling function `get_events`. - -See the endpoint docs at -[API Reference](https://developer.box.com/reference/get-events/). - - - -```python -client.events.get_events( - stream_type=GetEventsStreamType.ADMIN_LOGS.value, - limit=1, - created_after=created_after_date, - created_before=created_before_date, -) -``` - -### Arguments - -- stream_type `Optional[GetEventsStreamType]` - - Defines the type of events that are returned _ `all` returns everything for a user and is the default _ `changes` returns events that may cause file tree changes such as file updates or collaborations. _ `sync` is similar to `changes` but only applies to synced folders _ `admin_logs` returns all events for an entire enterprise and requires the user making the API call to have admin permissions. This stream type is for programmatically pulling from a 1 year history of events across all users within the enterprise and within a `created_after` and `created_before` time frame. The complete history of events will be returned in chronological order based on the event time, but latency will be much higher than `admin_logs_streaming`. \* `admin_logs_streaming` returns all events for an entire enterprise and requires the user making the API call to have admin permissions. This stream type is for polling for recent events across all users within the enterprise. Latency will be much lower than `admin_logs`, but events will not be returned in chronological order and may contain duplicates. -- stream_position `Optional[str]` - - The location in the event stream to start receiving events from. _ `now` will return an empty list events and the latest stream position for initialization. _ `0` or `null` will return all events. -- limit `Optional[int]` - - Limits the number of events returned Note: Sometimes, the events less than the limit requested can be returned even when there may be more events remaining. This is primarily done in the case where a number of events have already been retrieved and these retrieved events are returned rather than delaying for an unknown amount of time to see if there are any more results. -- event_type `Optional[List[GetEventsEventType]]` - - A comma-separated list of events to filter by. This can only be used when requesting the events with a `stream_type` of `admin_logs` or `adming_logs_streaming`. For any other `stream_type` this value will be ignored. -- created_after `Optional[DateTime]` - - The lower bound date and time to return events for. This can only be used when requesting the events with a `stream_type` of `admin_logs`. For any other `stream_type` this value will be ignored. -- created_before `Optional[DateTime]` - - The upper bound date and time to return events for. This can only be used when requesting the events with a `stream_type` of `admin_logs`. For any other `stream_type` this value will be ignored. -- extra_headers `Optional[Dict[str, Optional[str]]]` - - Extra headers that will be included in the HTTP request. - -### Returns - -This function returns a value of type `Events`. - -Returns a list of event objects. - -Events objects are returned in pages, with each page (chunk) -including a list of event objects. The response includes a -`chunk_size` parameter indicating how many events were returned in this -chunk, as well as the next `stream_position` that can be -queried. +- [List user and enterprise events](#list-user-and-enterprise-events) ## Get events long poll endpoint @@ -118,3 +61,60 @@ This function returns a value of type `RealtimeServers`. Returns a paginated array of servers that can be used instead of the regular endpoints for long-polling events. + +## List user and enterprise events + +Returns up to a year of past events for a given user +or for the entire enterprise. + +By default this returns events for the authenticated user. To retrieve events +for the entire enterprise, set the `stream_type` to `admin_logs_streaming` +for live monitoring of new events, or `admin_logs` for querying across +historical events. The user making the API call will +need to have admin privileges, and the application will need to have the +scope `manage enterprise properties` checked. + +This operation is performed by calling function `get_events`. + +See the endpoint docs at +[API Reference](https://developer.box.com/reference/get-events/). + + + +```python +client.events.get_events( + stream_type=GetEventsStreamType.ADMIN_LOGS.value, + limit=1, + created_after=created_after_date, + created_before=created_before_date, +) +``` + +### Arguments + +- stream_type `Optional[GetEventsStreamType]` + - Defines the type of events that are returned _ `all` returns everything for a user and is the default _ `changes` returns events that may cause file tree changes such as file updates or collaborations. _ `sync` is similar to `changes` but only applies to synced folders _ `admin_logs` returns all events for an entire enterprise and requires the user making the API call to have admin permissions. This stream type is for programmatically pulling from a 1 year history of events across all users within the enterprise and within a `created_after` and `created_before` time frame. The complete history of events will be returned in chronological order based on the event time, but latency will be much higher than `admin_logs_streaming`. \* `admin_logs_streaming` returns all events for an entire enterprise and requires the user making the API call to have admin permissions. This stream type is for polling for recent events across all users within the enterprise. Latency will be much lower than `admin_logs`, but events will not be returned in chronological order and may contain duplicates. +- stream_position `Optional[str]` + - The location in the event stream to start receiving events from. _ `now` will return an empty list events and the latest stream position for initialization. _ `0` or `null` will return all events. +- limit `Optional[int]` + - Limits the number of events returned Note: Sometimes, the events less than the limit requested can be returned even when there may be more events remaining. This is primarily done in the case where a number of events have already been retrieved and these retrieved events are returned rather than delaying for an unknown amount of time to see if there are any more results. +- event_type `Optional[List[GetEventsEventType]]` + - A comma-separated list of events to filter by. This can only be used when requesting the events with a `stream_type` of `admin_logs` or `adming_logs_streaming`. For any other `stream_type` this value will be ignored. +- created_after `Optional[DateTime]` + - The lower bound date and time to return events for. This can only be used when requesting the events with a `stream_type` of `admin_logs`. For any other `stream_type` this value will be ignored. +- created_before `Optional[DateTime]` + - The upper bound date and time to return events for. This can only be used when requesting the events with a `stream_type` of `admin_logs`. For any other `stream_type` this value will be ignored. +- extra_headers `Optional[Dict[str, Optional[str]]]` + - Extra headers that will be included in the HTTP request. + +### Returns + +This function returns a value of type `Events`. + +Returns a list of event objects. + +Events objects are returned in pages, with each page (chunk) +including a list of event objects. The response includes a +`chunk_size` parameter indicating how many events were returned in this +chunk, as well as the next `stream_position` that can be +queried. diff --git a/docs/file_versions.md b/docs/file_versions.md index 6c03dea..ae4f6b3 100644 --- a/docs/file_versions.md +++ b/docs/file_versions.md @@ -2,8 +2,8 @@ - [List all file versions](#list-all-file-versions) - [Get file version](#get-file-version) -- [Restore file version](#restore-file-version) - [Remove file version](#remove-file-version) +- [Restore file version](#restore-file-version) - [Promote file version](#promote-file-version) ## List all file versions @@ -85,24 +85,21 @@ Not all available fields are returned by default. Use the [fields](#param-fields) query parameter to explicitly request any specific fields. -## Restore file version +## Remove file version -Restores a specific version of a file after it was deleted. -Don't use this endpoint to restore Box Notes, -as it works with file formats such as PDF, DOC, -PPTX or similar. +Move a file version to the trash. -This operation is performed by calling function `update_file_version_by_id`. +Versions are only tracked for Box users with premium accounts. + +This operation is performed by calling function `delete_file_version_by_id`. See the endpoint docs at -[API Reference](https://developer.box.com/reference/put-files-id-versions-id/). +[API Reference](https://developer.box.com/reference/delete-files-id-versions-id/). - + ```python -client.file_versions.update_file_version_by_id( - file.id, file_version.id, trashed_at=create_null() -) +client.file_versions.delete_file_version_by_id(file.id, file_version.id) ``` ### Arguments @@ -111,32 +108,36 @@ client.file_versions.update_file_version_by_id( - The unique identifier that represents a file. The ID for any file can be determined by visiting a file in the web application and copying the ID from the URL. For example, for the URL `https://*.app.box.com/files/123` the `file_id` is `123`. Example: "12345" - file_version_id `str` - The ID of the file version Example: "1234" -- trashed_at `Optional[str]` - - Set this to `null` to clear the date and restore the file. +- if_match `Optional[str]` + - Ensures this item hasn't recently changed before making changes. Pass in the item's last observed `etag` value into this header and the endpoint will fail with a `412 Precondition Failed` if it has changed since. - extra_headers `Optional[Dict[str, Optional[str]]]` - Extra headers that will be included in the HTTP request. ### Returns -This function returns a value of type `FileVersionFull`. - -Returns a restored file version object. +This function returns a value of type `None`. -## Remove file version +Returns an empty response when the file has been successfully +deleted. -Move a file version to the trash. +## Restore file version -Versions are only tracked for Box users with premium accounts. +Restores a specific version of a file after it was deleted. +Don't use this endpoint to restore Box Notes, +as it works with file formats such as PDF, DOC, +PPTX or similar. -This operation is performed by calling function `delete_file_version_by_id`. +This operation is performed by calling function `update_file_version_by_id`. See the endpoint docs at -[API Reference](https://developer.box.com/reference/delete-files-id-versions-id/). +[API Reference](https://developer.box.com/reference/put-files-id-versions-id/). - + ```python -client.file_versions.delete_file_version_by_id(file.id, file_version.id) +client.file_versions.update_file_version_by_id( + file.id, file_version.id, trashed_at=create_null() +) ``` ### Arguments @@ -145,17 +146,16 @@ client.file_versions.delete_file_version_by_id(file.id, file_version.id) - The unique identifier that represents a file. The ID for any file can be determined by visiting a file in the web application and copying the ID from the URL. For example, for the URL `https://*.app.box.com/files/123` the `file_id` is `123`. Example: "12345" - file_version_id `str` - The ID of the file version Example: "1234" -- if_match `Optional[str]` - - Ensures this item hasn't recently changed before making changes. Pass in the item's last observed `etag` value into this header and the endpoint will fail with a `412 Precondition Failed` if it has changed since. +- trashed_at `Optional[str]` + - Set this to `null` to clear the date and restore the file. - extra_headers `Optional[Dict[str, Optional[str]]]` - Extra headers that will be included in the HTTP request. ### Returns -This function returns a value of type `None`. +This function returns a value of type `FileVersionFull`. -Returns an empty response when the file has been successfully -deleted. +Returns a restored file version object. ## Promote file version diff --git a/docs/shield_information_barrier_segments.md b/docs/shield_information_barrier_segments.md index c228e88..71a52c2 100644 --- a/docs/shield_information_barrier_segments.md +++ b/docs/shield_information_barrier_segments.md @@ -1,8 +1,8 @@ # ShieldInformationBarrierSegmentsManager - [Get shield information barrier segment with specified ID](#get-shield-information-barrier-segment-with-specified-id) -- [Update shield information barrier segment with specified ID](#update-shield-information-barrier-segment-with-specified-id) - [Delete shield information barrier segment](#delete-shield-information-barrier-segment) +- [Update shield information barrier segment with specified ID](#update-shield-information-barrier-segment-with-specified-id) - [List shield information barrier segments](#list-shield-information-barrier-segments) - [Create shield information barrier segment](#create-shield-information-barrier-segment) @@ -36,20 +36,21 @@ This function returns a value of type `ShieldInformationBarrierSegment`. Returns the shield information barrier segment object. -## Update shield information barrier segment with specified ID +## Delete shield information barrier segment -Updates the shield information barrier segment based on provided ID.. +Deletes the shield information barrier segment +based on provided ID. -This operation is performed by calling function `update_shield_information_barrier_segment_by_id`. +This operation is performed by calling function `delete_shield_information_barrier_segment_by_id`. See the endpoint docs at -[API Reference](https://developer.box.com/reference/put-shield-information-barrier-segments-id/). +[API Reference](https://developer.box.com/reference/delete-shield-information-barrier-segments-id/). - + ```python -client.shield_information_barrier_segments.update_shield_information_barrier_segment_by_id( - segment_id, description=updated_segment_description +client.shield_information_barrier_segments.delete_shield_information_barrier_segment_by_id( + segment.id ) ``` @@ -57,34 +58,29 @@ client.shield_information_barrier_segments.update_shield_information_barrier_seg - shield_information_barrier_segment_id `str` - The ID of the shield information barrier segment. Example: "3423" -- name `Optional[str]` - - The updated name for the shield information barrier segment. -- description `Optional[str]` - - The updated description for the shield information barrier segment. - extra_headers `Optional[Dict[str, Optional[str]]]` - Extra headers that will be included in the HTTP request. ### Returns -This function returns a value of type `ShieldInformationBarrierSegment`. +This function returns a value of type `None`. -Returns the updated shield information barrier segment object. +Empty body in response -## Delete shield information barrier segment +## Update shield information barrier segment with specified ID -Deletes the shield information barrier segment -based on provided ID. +Updates the shield information barrier segment based on provided ID.. -This operation is performed by calling function `delete_shield_information_barrier_segment_by_id`. +This operation is performed by calling function `update_shield_information_barrier_segment_by_id`. See the endpoint docs at -[API Reference](https://developer.box.com/reference/delete-shield-information-barrier-segments-id/). +[API Reference](https://developer.box.com/reference/put-shield-information-barrier-segments-id/). - + ```python -client.shield_information_barrier_segments.delete_shield_information_barrier_segment_by_id( - segment.id +client.shield_information_barrier_segments.update_shield_information_barrier_segment_by_id( + segment_id, description=updated_segment_description ) ``` @@ -92,14 +88,18 @@ client.shield_information_barrier_segments.delete_shield_information_barrier_seg - shield_information_barrier_segment_id `str` - The ID of the shield information barrier segment. Example: "3423" +- name `Optional[str]` + - The updated name for the shield information barrier segment. +- description `Optional[str]` + - The updated description for the shield information barrier segment. - extra_headers `Optional[Dict[str, Optional[str]]]` - Extra headers that will be included in the HTTP request. ### Returns -This function returns a value of type `None`. +This function returns a value of type `ShieldInformationBarrierSegment`. -Empty body in response +Returns the updated shield information barrier segment object. ## List shield information barrier segments diff --git a/docs/uploads.md b/docs/uploads.md index ceba741..b94b616 100644 --- a/docs/uploads.md +++ b/docs/uploads.md @@ -1,8 +1,8 @@ # UploadsManager - [Upload file version](#upload-file-version) -- [Upload file](#upload-file) - [Preflight check before upload](#preflight-check-before-upload) +- [Upload file](#upload-file) ## Upload file version @@ -54,6 +54,36 @@ This function returns a value of type `Files`. Returns the new file object in a list. +## Preflight check before upload + +Performs a check to verify that a file will be accepted by Box +before you upload the entire file. + +This operation is performed by calling function `preflight_file_upload_check`. + +See the endpoint docs at +[API Reference](https://developer.box.com/reference/options-files-content/). + +_Currently we don't have an example for calling `preflight_file_upload_check` in integration tests_ + +### Arguments + +- name `Optional[str]` + - The name for the file +- size `Optional[int]` + - The size of the file in bytes +- parent `Optional[PreflightFileUploadCheckParent]` + - +- extra_headers `Optional[Dict[str, Optional[str]]]` + - Extra headers that will be included in the HTTP request. + +### Returns + +This function returns a value of type `UploadUrl`. + +If the check passed, the response will include a session URL that +can be used to upload the file to. + ## Upload file Uploads a small file to Box. For file sizes over 50MB we recommend @@ -102,33 +132,3 @@ parent_client.uploads.upload_file( This function returns a value of type `Files`. Returns the new file object in a list. - -## Preflight check before upload - -Performs a check to verify that a file will be accepted by Box -before you upload the entire file. - -This operation is performed by calling function `preflight_file_upload_check`. - -See the endpoint docs at -[API Reference](https://developer.box.com/reference/options-files-content/). - -_Currently we don't have an example for calling `preflight_file_upload_check` in integration tests_ - -### Arguments - -- name `Optional[str]` - - The name for the file -- size `Optional[int]` - - The size of the file in bytes -- parent `Optional[PreflightFileUploadCheckParent]` - - -- extra_headers `Optional[Dict[str, Optional[str]]]` - - Extra headers that will be included in the HTTP request. - -### Returns - -This function returns a value of type `UploadUrl`. - -If the check passed, the response will include a session URL that -can be used to upload the file to. diff --git a/setup.py b/setup.py index 0f70c6c..4b727f3 100644 --- a/setup.py +++ b/setup.py @@ -22,9 +22,8 @@ def main(): setup( name='box-sdk-gen', version=__version__, - description='[Box Platform](https://box.dev) provides functionality to provide access to content stored within [Box](https://box.com). It provides endpoints for basic manipulation of files and folders, management of users within an enterprise, as well as more complex topics such as legal holds and retention policies.', + description='Official Box Python Generated SDK', url='https://github.com/box/box-python-sdk-gen.git', - licence='Apache-2.0, http://www.apache.org/licenses/LICENSE-2.0', author='Box', long_description_content_type='text/markdown', long_description=open( diff --git a/test/fetch.py b/test/fetch.py index 97471a8..52cb636 100644 --- a/test/fetch.py +++ b/test/fetch.py @@ -6,7 +6,13 @@ from unittest.mock import Mock, patch from requests import Session, Response, RequestException -from box_sdk_gen import NetworkSession, BoxAPIError, Authentication, BoxSDKError +from box_sdk_gen import ( + NetworkSession, + BoxAPIError, + Authentication, + BoxSDKError, + BoxClient, +) from box_sdk_gen.networking.fetch import ( fetch, FetchOptions, @@ -22,6 +28,7 @@ APIResponse, MultipartItem, ) +from box_sdk_gen.networking.proxy_config import ProxyConfig @pytest.fixture @@ -810,3 +817,13 @@ def test_raising_exception_raised_by_network_layer(): assert e.message == "Something went wrong" assert e.error == requests_exception assert e.name == 'BoxSDKError' + + +def test_proxy_config(): + client = BoxClient(auth=None).with_proxy( + ProxyConfig(url="http://127.0.0.1:3128/", username="user", password="pass") + ) + assert client.network_session.proxy_url == 'http://user:pass@127.0.0.1:3128/' + requests_session = client.network_session.requests_session + assert requests_session.proxies['http'] == 'http://user:pass@127.0.0.1:3128/' + assert requests_session.proxies['https'] == 'http://user:pass@127.0.0.1:3128/'